home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / trn / part08 < prev    next >
Encoding:
Internet Message Format  |  1991-12-02  |  81.9 KB

  1. Subject:  v25i011:  trn 2.0 - threaded newsreader based on rn 4.4, Part08/13
  2. Newsgroups: comp.sources.unix
  3. Approved: vixie@pa.dec.com
  4.  
  5. Submitted-by: davison@borland.com (Wayne Davison)
  6. Posting-number: Volume 25, Issue 11
  7. Archive-name: trn/part08
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 8 (of 13)."
  16. # Contents:  art.c common.h term.c
  17. # Wrapped by vixie@cognition.pa.dec.com on Tue Dec  3 16:34:55 1991
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'art.c' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'art.c'\"
  21. else
  22. echo shar: Extracting \"'art.c'\" \(25485 characters\)
  23. sed "s/^X//" >'art.c' <<'END_OF_FILE'
  24. X/* $Id: art.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  25. X *
  26. X *
  27. X * 
  28. X */
  29. X/* This software is Copyright 1991 by Stan Barber. 
  30. X *
  31. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  32. X * use this software as long as: there is no monetary profit gained
  33. X * specifically from the use or reproduction of this software, it is not
  34. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  35. X * included prominently in any copy made. 
  36. X *
  37. X * The author make no claims as to the fitness or correctness of this software
  38. X * for any use whatsoever, and it is provided as is. Any use of this software
  39. X * is at the user's own risk. 
  40. X */
  41. X
  42. X#include "EXTERN.h"
  43. X#include "common.h"
  44. X#include "rn.h"
  45. X#include "ngstuff.h"
  46. X#include "ngdata.h"
  47. X#include "head.h"
  48. X#include "cheat.h"
  49. X#include "help.h"
  50. X#include "search.h"
  51. X#include "artio.h"
  52. X#include "ng.h"
  53. X#include "bits.h"
  54. X#include "final.h"
  55. X#include "artstate.h"
  56. X#include "rcstuff.h"
  57. X#include "term.h"
  58. X#include "sw.h"
  59. X#include "util.h"
  60. X#include "backpage.h"
  61. X#include "intrp.h"
  62. X#ifdef USETHREADS
  63. X#include "threads.h"
  64. X#include "rthreads.h"
  65. X#endif
  66. X#include "INTERN.h"
  67. X#include "art.h"
  68. X
  69. X/* page_switch() return values */
  70. X
  71. X#define PS_NORM 0
  72. X#define PS_ASK 1
  73. X#define PS_RAISE 2
  74. X#define PS_TOEND 3
  75. X
  76. bool special = FALSE;        /* is next page special length? */
  77. int slines = 0;            /* how long to make page when special */
  78. ART_LINE highlight = -1;    /* next line to be highlighted */
  79. char *restart = Nullch;        /* if nonzero, the place where last */
  80. X                /* line left off on line split */
  81. char *blinebeg;            /* where in buffer current line began */
  82. ART_POS alinebeg;        /* where in file current line began */
  83. X
  84. X#ifdef INNERSEARCH
  85. ART_POS innersearch = 0;    /* artpos of end of line we found */
  86. X                /* for 'g' command */
  87. ART_LINE isrchline = 0;            /* last line to display */
  88. bool hide_everything = FALSE;
  89. X                /* if set, do not write page now, */
  90. X                /* but refresh when done with page */
  91. COMPEX gcompex;                /* in article search pattern */
  92. X#endif
  93. X
  94. bool firstpage;            /* is this the 1st page of article? */
  95. X
  96. char art_buf[LBUFLEN];        /* place for article lines */
  97. X
  98. void
  99. art_init()
  100. X{
  101. X    ;
  102. X}
  103. X
  104. int
  105. do_article()
  106. X{
  107. X    register char *s;
  108. X    ART_POS artsize;            /* size in bytes of article */
  109. X    bool hide_this_line = FALSE;    /* hidden header line? */
  110. X    ART_LINE linenum;    /* line # on page, 1 origin */
  111. X#ifdef ULSMARTS
  112. X    bool under_lining = FALSE;
  113. X                /* are we underlining a word? */
  114. X#endif
  115. X    register char *bufptr = art_buf;
  116. X                /* pointer to input buffer */
  117. X    register int outpos;    /* column position of output */
  118. X    static char prompt_buf[64];        /* place to hold prompt */
  119. X    bool notesfiles = FALSE;        /* might there be notesfiles junk? */
  120. X    char oldmode = mode;
  121. X    char *ctime();
  122. X
  123. X#ifdef INNERSEARCH
  124. X    register int outputok;
  125. X#endif
  126. X
  127. X    if (fstat(fileno(artfp),&filestat))
  128. X                /* get article file stats */
  129. X    return DA_CLEAN;
  130. X    if ((filestat.st_mode & S_IFMT) != S_IFREG)
  131. X    return DA_NORM;
  132. X    artsize = filestat.st_size;
  133. X                /* from that get article size */
  134. X    sprintf(prompt_buf,
  135. X    "%%sEnd of article %ld (of %ld)--what next? [%%s]",
  136. X    (long)art,(long)lastart);    /* format prompt string */
  137. X    prompt = prompt_buf;
  138. X    int_count = 0;        /* interrupt count is 0 */
  139. X    firstpage = (topline < 0);
  140. X    for (;;) {            /* for each page */
  141. X#ifdef USETHREADS
  142. X    if (ThreadedGroup && max_tree_lines)
  143. X        init_tree();    /* init tree display */
  144. X#endif
  145. X    assert(art == openart);
  146. X    if (do_fseek) {
  147. X#ifdef ASYNC_PARSE
  148. X        parse_maybe(art);        /* make sure header is ours */
  149. X#endif
  150. X        artpos = vrdary(artline);
  151. X        if (artpos < 0)
  152. X        artpos = -artpos;    /* labs(), anyone? */
  153. X        if (firstpage)
  154. X        artpos = (ART_POS)0;
  155. X        fseek(artfp,artpos,0);
  156. X        if (artpos < htype[PAST_HEADER].ht_minpos)
  157. X        in_header = SOME_LINE;
  158. X        do_fseek = FALSE;
  159. X        restart = Nullch;
  160. X    }
  161. X    linenum = 1;
  162. X    if (firstpage) {
  163. X        if (firstline) {
  164. X        interp(art_buf, (sizeof art_buf), firstline);
  165. X#ifdef USETHREADS
  166. X        linenum += tree_puts(art_buf,linenum+topline,0);
  167. X#else
  168. X#ifdef CLEAREOL
  169. X        maybe_eol();    
  170. X#endif /* CLEAREOL */
  171. X        fputs(art_buf,stdout) FLUSH;
  172. X        linenum++;
  173. X#endif
  174. X        artopen(art);        /* rewind article in case interp */
  175. X                    /* forced a header parse */
  176. X        } else 
  177. X            {
  178. X        ART_NUM i;
  179. X
  180. X#ifdef USETHREADS
  181. X        if (ThreadedGroup) {
  182. X            int selected, unseen;
  183. X
  184. X            selected = curr_p_art
  185. X                && (selected_roots[curr_p_art->root] & 1);
  186. X            unseen = !was_read(art);
  187. X            sprintf(art_buf,"%s%s #%ld",ngname,moderated,(long)art);
  188. X            if (selected_root_cnt) {
  189. X            i = selected_count - (unseen && selected);
  190. X            sprintf(art_buf+strlen(art_buf)," (%ld + %ld more)",
  191. X                (long)i,(long)toread[ng] - selected_count
  192. X                    - unthreaded - (!selected && unseen));
  193. X            }
  194. X            else if ((i = (ART_NUM)(toread[ng]-unthreaded-unseen)) != 0)
  195. X            sprintf(art_buf+strlen(art_buf)," (%ld more)",(long)i);
  196. X            linenum += tree_puts(art_buf,linenum+topline,0);
  197. X        }
  198. X        else
  199. X#endif
  200. X        {
  201. X#ifdef CLEAREOL
  202. X            maybe_eol();    
  203. X#endif /* CLEAREOL */
  204. X            printf("Article %ld",(long)art);
  205. X            i = (ART_NUM)(toread[ng] - 1 + was_read(art));
  206. X#ifdef DELAYMARK
  207. X            if ((i > 0) || dmcount) {
  208. X            printf(" (%ld more",(long)i);
  209. X            if (dmcount)
  210. X                printf(" + %ld Marked to return",(long)dmcount);
  211. X            putchar(')');
  212. X            }
  213. X#else
  214. X            if (i > 0)
  215. X            printf(" (%ld more)",(long)i);
  216. X#endif
  217. X            if (htype[NGS_LINE].ht_flags & HT_HIDE)
  218. X            printf(" in %s", ngname);
  219. X            fputs(moderated,stdout);
  220. X            fputs(":\n",stdout) FLUSH;
  221. X            linenum++;
  222. X        }
  223. X        }
  224. X        start_header(art);
  225. X        forcelast = FALSE;        /* we will have our day in court */
  226. X        restart = Nullch;
  227. X        artline = 0;        /* start counting lines */
  228. X        artpos = 0;
  229. X        vwtary(artline,artpos);    /* remember pos in file */
  230. X    }
  231. X    for (;                /* linenum already set */
  232. X      in_header || (
  233. X#ifdef INNERSEARCH
  234. X      innersearch ? innermore() :
  235. X#endif
  236. X      linenum<(firstpage?initlines:(special?slines:LINES)) );
  237. X      linenum++) {        /* for each line on page */
  238. X        if (int_count) {    /* exit via interrupt? */
  239. X        putchar('\n') FLUSH;    /* get to left margin */
  240. X        int_count = 0;    /* reset interrupt count */
  241. X        mode = oldmode;
  242. X        special = FALSE;
  243. X        return DA_NORM;    /* skip out of loops */
  244. X        }
  245. X        if (restart) {        /* did not finish last line? */
  246. X        bufptr = restart;    /* then start again here */
  247. X        restart = Nullch;    /* and reset the flag */
  248. X        }
  249. X        else {            /* not a restart */
  250. X        if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
  251. X                    /* if all done */
  252. X            mode = oldmode;
  253. X            special = FALSE;
  254. X            return DA_NORM;    /* skip out of loops */
  255. X        }
  256. X        bufptr = art_buf;    /* so start at beginning */
  257. X        art_buf[LBUFLEN-1] = '\0';
  258. X                    /* make sure string ends */
  259. X        }
  260. X        blinebeg = bufptr;    /* remember where we began */
  261. X        alinebeg = artpos;    /* both in buffer and file */
  262. X        if (in_header && bufptr == art_buf) {
  263. X        hide_this_line =
  264. X            parseline(art_buf,do_hiding,hide_this_line);
  265. X#ifdef USETHREADS
  266. X        if (!in_header) {
  267. X            linenum += finish_tree(linenum+topline);
  268. X        }
  269. X#endif
  270. X        } else if (notesfiles && do_hiding &&
  271. X          bufptr == art_buf && *art_buf == '#' &&
  272. X          isupper(art_buf[1]) && art_buf[2] == ':' ) {
  273. X        fgets(art_buf,sizeof(art_buf),artfp);
  274. X        if (index(art_buf,'!') != Nullch)
  275. X            fgets(art_buf,sizeof(art_buf),artfp);
  276. X        htype[PAST_HEADER].ht_minpos = ftell(artfp);
  277. X                    /* exclude notesfiles droppings */
  278. X        hide_this_line = TRUE;    /* and do not print either */
  279. X        notesfiles = FALSE;
  280. X        }
  281. X#ifdef CUSTOMLINES
  282. X        if (hideline && bufptr == art_buf &&
  283. X          execute(&hide_compex,art_buf) )
  284. X        hide_this_line = TRUE;
  285. X#endif
  286. X        if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
  287. X        if (in_header == NGS_LINE) {
  288. X            if ((s = index(art_buf,'\n')) != Nullch)
  289. X            *s = '\0';
  290. X            hide_this_line = (index(art_buf,',') == Nullch)
  291. X            && strEQ(art_buf+12, ngname);
  292. X            if (s != Nullch)
  293. X            *s = '\n';
  294. X        }
  295. X        else if (in_header == EXPIR_LINE) {
  296. X            if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
  297. X            hide_this_line = (strlen(art_buf) < 10);
  298. X        }
  299. X        else if (in_header == FROM_LINE) {
  300. X            if (do_hiding && (s = index(art_buf+6,'(')) != Nullch) {
  301. X            strcpy(art_buf+6,s+1);
  302. X            if((s = rindex(art_buf+6,')')) != Nullch)
  303. X                *s = '\0';
  304. X            }
  305. X        }
  306. X#ifdef USETHREADS
  307. X        else if (in_header == DATE_LINE && curr_p_art && do_hiding) {
  308. X            strftime(art_buf+6, sizeof(art_buf)-6,
  309. X            getval("LOCALTIMEFMT", LOCALTIMEFMT),
  310. X            localtime(&curr_p_art->date));
  311. X        }
  312. X#endif
  313. X        }
  314. X        if (in_header == SUBJ_LINE &&
  315. X        htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
  316. X                /* is this the subject? */
  317. X        int length;
  318. X#ifndef USETHREADS
  319. X        char sp;
  320. X#endif
  321. X
  322. X        length = strlen(art_buf)-1;
  323. X        artline++;
  324. X        art_buf[length] = '\0';        /* wipe out newline */
  325. X#ifdef NOFIREWORKS
  326. X        no_ulfire();
  327. X#endif
  328. X        notesfiles =
  329. X            (instr(&art_buf[length-10]," - (nf", TRUE) != Nullch);
  330. X#ifdef USETHREADS
  331. X        /* tree_puts(, ,1) underlines subject */
  332. X        linenum += tree_puts(art_buf,linenum+topline,1)-1;
  333. X#else
  334. X        if (oldsubject) {
  335. X            length += 7;
  336. X            fputs("(SAME) ",stdout);
  337. X            oldsubject = FALSE;
  338. X        }
  339. X        if (length+UG > COLS) {        /* rarely true */
  340. X            linenum++;
  341. X            vwtary(artline,vrdary(artline-1)+COLS);
  342. X            artline++;
  343. X        }
  344. X#ifdef CLEAREOL
  345. X        maybe_eol();    
  346. X#endif /* CLEAREOL */
  347. X        /* Find the point where the subject text starts. */
  348. X        s = art_buf;
  349. X        if (!isspace(*s)) {
  350. X            /* This is the first subject line, not a continuation
  351. X               line.  Skip past the "Subject:" */
  352. X            s += 8;
  353. X        }
  354. X        /* Skip past any whitespace. */
  355. X        while (isspace(*s)) ++s;
  356. X
  357. X        /* Split the string in two at the whitespace. */
  358. X        sp = *(s-1);
  359. X        *(s-1) = '\0';
  360. X
  361. X        fputs(art_buf, stdout) FLUSH;
  362. X
  363. X        /* On an UGly terminal, the start-underline magic cookie
  364. X           takes up space, so we steal a space from the subject
  365. X           line.  This is not quite right for tabs; oh well. */
  366. X        if (!UG)
  367. X            putchar(sp);
  368. X
  369. X        underprint(s);    /* print subject underlined */
  370. X        putchar('\n') FLUSH;    /* and finish the line */
  371. X#endif
  372. X        }
  373. X        else if (hide_this_line && do_hiding) {
  374. X                    /* do not print line? */
  375. X        linenum--;        /* compensate for linenum++ */
  376. X        if (!in_header)
  377. X            hide_this_line = FALSE;
  378. X        }
  379. X#ifdef USETHREADS
  380. X        else if (in_header) {
  381. X        artline++;
  382. X        linenum += tree_puts(art_buf,linenum+topline,0)-1;
  383. X        }
  384. X#endif
  385. X        else {            /* just a normal line */
  386. X        if (highlight==artline) {    /* this line to be highlit? */
  387. X            if (marking == STANDOUT) {
  388. X#ifdef NOFIREWORKS
  389. X            if (erase_screen)
  390. X                no_sofire();
  391. X#endif
  392. X            standout();
  393. X            }
  394. X            else {
  395. X#ifdef NOFIREWORKS
  396. X            if (erase_screen)
  397. X                no_ulfire();
  398. X#endif
  399. X            underline();
  400. X            }
  401. X            if (*bufptr == '\n')
  402. X            putchar(' ');
  403. X        }
  404. X#ifdef INNERSEARCH
  405. X        outputok = !hide_everything;
  406. X                    /* get it into register, hopefully */
  407. X#endif
  408. X#ifdef CLEAREOL
  409. X#ifdef INNERSEARCH
  410. X        if (outputok)
  411. X#endif
  412. X        maybe_eol();    
  413. X#endif /* CLEAREOL */
  414. X#ifdef CUSTOMLINES
  415. X        if (pagestop && bufptr == art_buf && 
  416. X          execute(&page_compex,art_buf) )
  417. X            linenum = 32700;
  418. X#endif
  419. X        for (outpos = 0; outpos < COLS; ) {
  420. X                    /* while line has room */
  421. X            if (*(unsigned char *)bufptr >= ' ') { /* normal char? */
  422. X#ifdef ULSMARTS
  423. X            if (*bufptr == '_') {
  424. X                if (bufptr[1] == '\b') {
  425. X                if (!under_lining && highlight!=artline
  426. X#ifdef INNERSEARCH
  427. X                    && outputok
  428. X#endif
  429. X                    ) {
  430. X                    under_lining++;
  431. X                    if (UG) {
  432. X                    if (bufptr != buf &&
  433. X                      bufptr[-1] == ' ') {
  434. X                        outpos--;
  435. X                        backspace();
  436. X                    }
  437. X                    }
  438. X                    underline();
  439. X                }
  440. X                bufptr += 2;
  441. X                }
  442. X            }
  443. X            else {
  444. X                if (under_lining) {
  445. X                under_lining = 0;
  446. X                un_underline();
  447. X                if (UG) {
  448. X                    if (*bufptr == ' ')
  449. X                    goto skip_put;
  450. X                    outpos++;
  451. X                }
  452. X                }
  453. X            }
  454. X#endif
  455. X#ifdef INNERSEARCH
  456. X            if (outputok)
  457. X#endif
  458. X            {
  459. X#ifdef ROTATION
  460. X                if (rotate && !in_header
  461. X                  && isalpha(*bufptr)) {
  462. X                if ((*bufptr & 31) <= 13)
  463. X                    putchar(*bufptr+13);
  464. X                else
  465. X                    putchar(*bufptr-13);
  466. X                }
  467. X                else
  468. X#endif
  469. X                putchar(*bufptr);
  470. X            }
  471. X            if (*UC && ((highlight==artline && marking == 1)
  472. X#ifdef ULSMARTS
  473. X                || under_lining
  474. X#endif
  475. X                )) {
  476. X                backspace();
  477. X                underchar();
  478. X            }
  479. X            skip_put:
  480. X            bufptr++;
  481. X            outpos++;
  482. X            }
  483. X            else if (*bufptr == '\n' || !*bufptr) {
  484. X                            /* newline? */
  485. X#ifdef ULSMARTS
  486. X            if (under_lining) {
  487. X                under_lining = 0;
  488. X                un_underline();
  489. X            }
  490. X#endif
  491. X#ifdef DEBUGGING
  492. X            if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
  493. X                standout();
  494. X                printf("%4d",artline); 
  495. X                un_standout();
  496. X            }
  497. X#endif
  498. X#ifdef INNERSEARCH
  499. X            if (outputok)
  500. X#endif
  501. X                putchar('\n') FLUSH;
  502. X            restart = 0;
  503. X            outpos = 1000;    /* signal normal \n */
  504. X            }
  505. X            else if (*bufptr == '\t') {    /* tab? */
  506. X            int incpos =  8 - outpos % 8;
  507. X#ifdef INNERSEARCH
  508. X            if (outputok)
  509. X#endif
  510. X                if (GT)
  511. X                putchar(*bufptr);
  512. X                else
  513. X                while (incpos--) putchar(' ');
  514. X            bufptr++;
  515. X            outpos += 8 - outpos % 8;
  516. X            }
  517. X            else if (*bufptr == '\f') {    /* form feed? */
  518. X#ifdef INNERSEARCH
  519. X            if (outputok)
  520. X#endif
  521. X                fputs("^L",stdout);
  522. X            if (bufptr == blinebeg && highlight != artline)
  523. X                linenum = 32700;
  524. X                /* how is that for a magic number? */
  525. X            bufptr++;
  526. X            outpos += 2;
  527. X            }
  528. X            else {        /* other control char */
  529. X#ifdef INNERSEARCH
  530. X            if (outputok)
  531. X#endif
  532. X            {
  533. X                putchar('^');
  534. X                if (highlight == artline && *UC && marking == 1) {
  535. X                backspace();
  536. X                underchar();
  537. X                putchar(*bufptr+64);
  538. X                backspace();
  539. X                underchar();
  540. X                }
  541. X                else
  542. X                putchar(*bufptr+64);
  543. X            }
  544. X            bufptr++;
  545. X            outpos += 2;
  546. X            }
  547. X            
  548. X        } /* end of column loop */
  549. X
  550. X        if (outpos < 1000) {/* did line overflow? */
  551. X            restart = bufptr;
  552. X                    /* restart here next time */
  553. X            if (!AM || XN) {/* no automatic margins on tty? */
  554. X#ifdef INNERSEARCH            /* then move it down ourselves */
  555. X            if (outputok)
  556. X#endif
  557. X                putchar('\n') FLUSH;
  558. X            }
  559. X            if (*bufptr == '\n')    /* skip the newline */
  560. X            restart = 0;
  561. X        }
  562. X
  563. X        /* handle normal end of output line formalities */
  564. X
  565. X        if (highlight == artline) {
  566. X                    /* were we highlighting line? */
  567. X            if (marking == STANDOUT)
  568. X            un_standout();
  569. X            else
  570. X            un_underline();
  571. X            highlight = -1;    /* no more we are */
  572. X        }
  573. X        artline++;    /* count the line just printed */
  574. X        if (artline - LINES + 1 > topline)
  575. X                /* did we just scroll top line off? */
  576. X            topline = artline - LINES + 1;
  577. X                /* then recompute top line # */
  578. X        }
  579. X
  580. X        /* determine actual position in file */
  581. X
  582. X        if (restart)    /* stranded somewhere in the buffer? */
  583. X        artpos += restart - blinebeg;
  584. X                /* just calculate position */
  585. X        else        /* no, ftell will do */
  586. X        artpos = ftell(artfp);
  587. X                /* so do ftell */
  588. X        vwtary(artline,artpos);    /* remember pos in file */
  589. X    } /* end of line loop */
  590. X
  591. X#ifdef INNERSEARCH
  592. X    innersearch = 0;
  593. X    if (hide_everything) {
  594. X        hide_everything = FALSE;
  595. X        *buf = Ctl('l');
  596. X        goto fake_command;
  597. X    }
  598. X#endif
  599. X    if (linenum >= 32700)/* did last line have formfeed? */
  600. X        vwtary(artline-1,-vrdary(artline-1));
  601. X                /* remember by negating pos in file */
  602. X
  603. X    special = FALSE;    /* end of page, so reset page length */
  604. X    firstpage = FALSE;    /* and say it is not 1st time thru */
  605. X
  606. X    /* extra loop bombout */
  607. X
  608. X    if (artpos == artsize) {/* did we just now reach EOF? */
  609. X        mode = oldmode;
  610. X        return DA_NORM;    /* avoid --MORE--(100%) */
  611. X    }
  612. X
  613. X/* not done with this article, so pretend we are a pager */
  614. X
  615. reask_pager:            
  616. X    unflush_output();    /* disable any ^O in effect */
  617. X    standout();        /* enter standout mode */
  618. X    printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
  619. X    un_standout();    /* leave standout mode */
  620. X#ifdef CLEAREOL
  621. X     maybe_eol();
  622. X#endif
  623. X    fflush(stdout);
  624. X/* reinp_pager:                 /* unused, commented for lint */
  625. X    eat_typeahead();
  626. X#ifdef DEBUGGING
  627. X    if (debug & DEB_CHECKPOINTING) {
  628. X        printf("(%d %d %d)",checkcount,linenum,artline);
  629. X        fflush(stdout);
  630. X    }
  631. X#endif
  632. X    if (checkcount >= docheckwhen &&
  633. X      linenum == LINES &&
  634. X      (artline > 40 || checkcount >= docheckwhen+10) ) {
  635. X                /* while he is reading a whole page */
  636. X                /* in an article he is interested in */
  637. X        checkcount = 0;
  638. X        checkpoint_rc();    /* update .newsrc */
  639. X    }
  640. X    collect_subjects();        /* loads subject cache until */
  641. X                    /* input is pending */
  642. X    mode = 'p';
  643. X    getcmd(buf);
  644. X    if (errno) {
  645. X        if (LINES < 100 && !int_count)
  646. X        *buf = '\f';/* on CONT fake up refresh */
  647. X        else {
  648. X        *buf = 'q';    /* on INTR or paper just quit */
  649. X        }
  650. X    }
  651. X    carriage_return();
  652. X#ifndef CLEAREOL
  653. X    erase_eol();    /* and erase the prompt */
  654. X#else
  655. X    if (erase_screen && can_home_clear)    
  656. X        clear_rest();
  657. X    else
  658. X        erase_eol();    /* and erase the prompt */
  659. X#endif /* CLEAREOL */
  660. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  661. X    fflush(stdout);
  662. X
  663. X    fake_command:        /* used by innersearch */
  664. X#ifdef USETHREADS
  665. X    output_chase_phrase = TRUE;
  666. X#endif
  667. X
  668. X    /* parse and process pager command */
  669. X
  670. X    switch (page_switch()) {
  671. X    case PS_ASK:    /* reprompt "--MORE--..." */
  672. X        goto reask_pager;
  673. X    case PS_RAISE:    /* reparse on article level */
  674. X        mode = oldmode;
  675. X        return DA_RAISE;
  676. X    case PS_TOEND:    /* fast pager loop exit */
  677. X        mode = oldmode;
  678. X        return DA_TOEND;
  679. X    case PS_NORM:    /* display more article */
  680. X        break;
  681. X    }
  682. X    } /* end of page loop */
  683. X}
  684. X
  685. X/* process pager commands */
  686. X
  687. int
  688. page_switch()
  689. X{
  690. X    register char *s;
  691. X    
  692. X    switch (*buf) {
  693. X    case 'd':
  694. X    case Ctl('d'):    /* half page */
  695. X    special = TRUE;
  696. X    slines = LINES / 2 + 1;
  697. X    if (marking && *blinebeg != '\f'
  698. X#ifdef CUSTOMLINES
  699. X      && (!pagestop || blinebeg != art_buf ||
  700. X          !execute(&page_compex,blinebeg))
  701. X#endif
  702. X      ) {
  703. X        up_line();
  704. X        highlight = --artline;
  705. X        restart = blinebeg;
  706. X        artpos = alinebeg;
  707. X    }
  708. X    return PS_NORM;
  709. X    case '!':            /* shell escape */
  710. X    escapade();
  711. X    return PS_ASK;
  712. X#ifdef INNERSEARCH
  713. X    case Ctl('i'):
  714. X    gline = 3;
  715. X    sprintf(cmd_buf,"^[^%c]",*blinebeg);
  716. X    compile(&gcompex,cmd_buf,TRUE,TRUE);
  717. X    goto caseG;
  718. X    case Ctl('g'):
  719. X    gline = 3;
  720. X    compile(&gcompex,"^Subject:",TRUE,TRUE);
  721. X    goto caseG;
  722. X    case 'g':        /* in-article search */
  723. X    if (!finish_command(FALSE))/* get rest of command */
  724. X        return PS_ASK;
  725. X    s = buf+1;
  726. X    if (isspace(*s))
  727. X        s++;
  728. X    if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
  729. X                /* compile regular expression */
  730. X        printf("\n%s\n",s) FLUSH;
  731. X        return PS_ASK;
  732. X    }
  733. X    carriage_return();
  734. X    erase_eol();    /* erase the prompt */
  735. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  736. X    /* FALL THROUGH */
  737. X    caseG:
  738. X    case 'G': {
  739. X    /* ART_LINE lines_to_skip = 0; */
  740. X    ART_POS start_where;
  741. X
  742. X    if (gline < 0 || gline > LINES-2)
  743. X        gline = LINES-2;
  744. X#ifdef DEBUGGING
  745. X    if (debug & DEB_INNERSRCH)
  746. X        printf("Start here? %d  >=? %d\n",topline + gline + 1,artline)
  747. X          FLUSH;
  748. X#endif
  749. X    if (*buf == Ctl('i') || topline+gline+1 >= artline)
  750. X        start_where = artpos;
  751. X            /* in case we had a line wrap */
  752. X    else {
  753. X        start_where = vrdary(topline+gline+1);
  754. X        if (start_where < 0)
  755. X        start_where = -start_where;
  756. X    }
  757. X    if (start_where < htype[PAST_HEADER].ht_minpos)
  758. X        start_where = htype[PAST_HEADER].ht_minpos;
  759. X    fseek(artfp,(long)start_where,0);
  760. X    innersearch = 0; /* assume not found */
  761. X    while (fgets(buf, sizeof buf, artfp) != Nullch) {
  762. X        /* lines_to_skip++;         NOT USED NOW */
  763. X#ifdef DEBUGGING
  764. X        if (debug & DEB_INNERSRCH)
  765. X        printf("Test %s",buf) FLUSH;
  766. X#endif
  767. X        if (execute(&gcompex,buf) != Nullch) {
  768. X        innersearch = ftell(artfp);
  769. X        break;
  770. X        }
  771. X    }
  772. X    if (!innersearch) {
  773. X        fseek(artfp,artpos,0);
  774. X        fputs("(Not found)",stdout) FLUSH;
  775. X        return PS_ASK;
  776. X    }
  777. X#ifdef DEBUGGING
  778. X    if (debug & DEB_INNERSRCH)
  779. X        printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
  780. X          FLUSH;
  781. X#endif
  782. X    if (innersearch <= artpos) {    /* already on page? */
  783. X        if (innersearch < artpos) {
  784. X        artline = topline+1;
  785. X        while (vrdary(artline) < innersearch)
  786. X            artline++;
  787. X        }
  788. X        highlight = artline - 1;
  789. X#ifdef DEBUGGING
  790. X        if (debug & DEB_INNERSRCH)
  791. X        printf("@ %d\n",highlight) FLUSH;
  792. X#endif
  793. X        topline = highlight - gline;
  794. X        if (topline < -1)
  795. X        topline = -1;
  796. X        *buf = '\f';        /* fake up a refresh */
  797. X        innersearch = 0;
  798. X        return page_switch();
  799. X    }
  800. X    else {                /* who knows how many lines it is? */
  801. X        do_fseek = TRUE;
  802. X        hide_everything = TRUE;
  803. X    }
  804. X    return PS_NORM;
  805. X    }
  806. X#else
  807. X    case 'g': case 'G': case Ctl('g'):
  808. X    notincl("g");
  809. X    return PS_ASK;
  810. X#endif
  811. X    case '\n':        /* one line */
  812. X    special = TRUE;
  813. X    slines = 2;
  814. X    return PS_NORM;
  815. X#ifdef ROTATION
  816. X    case 'X':
  817. X    rotate = !rotate;
  818. X    /* FALL THROUGH */
  819. X#endif
  820. X    case 'l':
  821. X    case '\f':        /* refresh screen */
  822. X#ifdef DEBUGGING
  823. X    if (debug & DEB_INNERSRCH) {
  824. X        printf("Topline = %d",topline) FLUSH;
  825. X        gets(buf);
  826. X    }
  827. X#endif
  828. X    clear();
  829. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  830. X    do_fseek = TRUE;
  831. X    artline = topline;
  832. X    if (artline < 0)
  833. X        artline = 0;
  834. X    firstpage = (topline < 0);
  835. X    return PS_NORM;
  836. X    case 'b':
  837. X    case '\b':
  838. X    case Ctl('b'): {    /* back up a page */
  839. X    ART_LINE target;
  840. X
  841. X#ifndef CLEAREOL
  842. X    clear();
  843. X#else
  844. X    if (can_home_clear)    /* if we can home do it */
  845. X        home_cursor();
  846. X    else
  847. X        clear();
  848. X
  849. X#endif /* CLEAREOL */
  850. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  851. X    do_fseek = TRUE;    /* reposition article file */
  852. X    target = topline - (LINES - 2);
  853. X    artline = topline;
  854. X    if (artline >= 0) do {
  855. X        artline--;
  856. X    } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
  857. X    topline = artline;
  858. X            /* remember top line of screen */
  859. X            /*  (line # within article file) */
  860. X    if (artline < 0)
  861. X        artline = 0;
  862. X    firstpage = (topline < 0);
  863. X    return PS_NORM;
  864. X    }
  865. X    case 'h': {        /* help */
  866. X    int cmd;
  867. X
  868. X    if ((cmd = help_page()) > 0)
  869. X        pushchar(cmd);
  870. X    return PS_ASK;
  871. X    }
  872. X#ifdef USETHREADS
  873. X    case 't':        /* output thread data */
  874. X    page_line = 1;
  875. X    p_art = curr_p_art;
  876. X    entire_tree();
  877. X    return PS_ASK;
  878. X#endif
  879. X    case '\177':
  880. X    case '\0':        /* treat del,break as 'n' */
  881. X    *buf = 'n';
  882. X    /* FALL THROUGH */
  883. X    case 'k':    case 'K':
  884. X#ifdef USETHREADS
  885. X    case 'T':    case 'J':
  886. X#endif
  887. X    case 'n':    case 'N':    case Ctl('n'):
  888. X    case 's':    case 'S':
  889. X    case 'e':
  890. X    case 'u':
  891. X    case 'w':    case 'W':
  892. X    case '|':
  893. X    mark_as_read();        /* mark article as read */
  894. X    /* FALL THROUGH */
  895. X#ifdef USETHREADS
  896. X    case 'U':    case ',':
  897. X    case '<':    case '>':
  898. X    case '[':    case ']':
  899. X    case '{':    case '}':
  900. X    case '+':   case ':':
  901. X#endif
  902. X    case '#':
  903. X    case '$':
  904. X    case '&':
  905. X    case '-':
  906. X    case '.':
  907. X    case '/':
  908. X    case '1': case '2': case '3': case '4': case '5':
  909. X    case '6': case '7': case '8': case '9':
  910. X    case '=':
  911. X    case '?':
  912. X    case 'c':    case 'C':    
  913. X#ifdef DEBUGGING
  914. X    case 'D':
  915. X#endif
  916. X    case 'E':
  917. X    case 'f':    case 'F':    
  918. X    case 'j':
  919. X                case Ctl('k'):
  920. X    case 'm':    case 'M':    
  921. X    case 'p':    case 'P':    case Ctl('p'):    
  922. X        case 'Q':
  923. X    case 'r':    case 'R':    case Ctl('r'):
  924. X    case 'v':
  925. X        case 'Y':
  926. X#ifndef ROTATION
  927. X    case 'x':    case 'X':
  928. X#endif
  929. X    case Ctl('x'):
  930. X    case 'z':
  931. X    case '^':
  932. X
  933. X#ifdef ROTATION
  934. X    rotate = FALSE;
  935. X#endif
  936. X    reread = FALSE;
  937. X    do_hiding = TRUE;
  938. X    if (index("nNpP\016\020",*buf) == Nullch &&
  939. X      index("wWsSe:!&|/?123456789.",*buf) != Nullch) {
  940. X        setdfltcmd();
  941. X        standout();        /* enter standout mode */
  942. X        printf(prompt,mailcall,dfltcmd);
  943. X                /* print prompt, whatever it is */
  944. X        un_standout();    /* leave standout mode */
  945. X        putchar(' ');
  946. X        fflush(stdout);
  947. X    }
  948. X    return PS_RAISE;    /* and pretend we were at end */
  949. X#ifdef ROTATION
  950. X    case 'x':
  951. X    rotate = TRUE;
  952. X    /* FALL THROUGH */
  953. X#endif
  954. X    case 'y':
  955. X    case Ctl('v'):
  956. X                    /* Leaving it undocumented in case */
  957. X                    /* I want to steal the key--LAW */
  958. X    case ' ':    /* continue current article */
  959. X    if (erase_screen) {    /* -e? */
  960. X#ifndef CLEAREOL
  961. X        clear();        /* clear screen */
  962. X#else
  963. X        if (can_home_clear)    /* if we can home do it */
  964. X        home_cursor();
  965. X        else
  966. X        clear();    /* else clear screen */
  967. X
  968. X#endif /* CLEAREOL */
  969. X        carriage_return();    /* Resets kernel's tab column counter to 0 */
  970. X        fflush(stdout);
  971. X
  972. X        if (*blinebeg != '\f'
  973. X#ifdef CUSTOMLINES
  974. X          && (!pagestop || blinebeg != art_buf ||
  975. X              !execute(&page_compex,blinebeg))
  976. X#endif
  977. X          ) {
  978. X        restart = blinebeg;
  979. X        artline--;     /* restart this line */
  980. X        artpos = alinebeg;
  981. X        if (marking)    /* and mark repeated line */
  982. X            highlight = artline;
  983. X        }
  984. X        topline = artline;
  985. X            /* and remember top line of screen */
  986. X            /*  (line # within article file) */
  987. X    }
  988. X    else if (marking && *blinebeg != '\f'
  989. X#ifdef CUSTOMLINES
  990. X      && (!pagestop || blinebeg != art_buf ||
  991. X          !execute(&page_compex,blinebeg))
  992. X#endif
  993. X      ) {
  994. X                /* are we marking repeats? */
  995. X        up_line();        /* go up one line */
  996. X        highlight = --artline;/* and get ready to highlight */
  997. X        restart = blinebeg;    /*   the old line */
  998. X        artpos = alinebeg;
  999. X    }
  1000. X    return PS_NORM;
  1001. X    case 'q':    /* quit this article? */
  1002. X    do_hiding = TRUE;
  1003. X    return PS_TOEND;
  1004. X    default:
  1005. X    fputs(hforhelp,stdout) FLUSH;
  1006. X    settle_down();
  1007. X    return PS_ASK;
  1008. X    }
  1009. X}
  1010. X
  1011. X#ifdef INNERSEARCH
  1012. bool
  1013. innermore()
  1014. X{
  1015. X    if (artpos < innersearch) {        /* not even on page yet? */
  1016. X#ifdef DEBUGGING
  1017. X    if (debug & DEB_INNERSRCH)
  1018. X        printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
  1019. X          FLUSH;
  1020. X#endif
  1021. X    return TRUE;
  1022. X    }
  1023. X    if (artpos == innersearch) {    /* just got onto page? */
  1024. X    isrchline = artline;        /* remember first line after */
  1025. X    highlight = artline - 1;
  1026. X#ifdef DEBUGGING
  1027. X    if (debug & DEB_INNERSRCH)
  1028. X        printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
  1029. X        (long)innersearch,hide_everything,highlight) FLUSH;
  1030. X#endif
  1031. X    if (hide_everything) {        /* forced refresh? */
  1032. X        topline = highlight - gline;
  1033. X        if (topline < -1)
  1034. X        topline = -1;
  1035. X        return FALSE;        /* let refresh do it all */
  1036. X    }
  1037. X    }
  1038. X#ifdef DEBUGGING
  1039. X    if (debug & DEB_INNERSRCH)
  1040. X    printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
  1041. X      FLUSH;
  1042. X#endif
  1043. X    if (artline < isrchline + gline) {
  1044. X    return TRUE;
  1045. X    }
  1046. X    return FALSE;
  1047. X}
  1048. X#endif
  1049. END_OF_FILE
  1050. if test 25485 -ne `wc -c <'art.c'`; then
  1051.     echo shar: \"'art.c'\" unpacked with wrong size!
  1052. fi
  1053. # end of 'art.c'
  1054. fi
  1055. if test -f 'common.h' -a "${1}" != "-c" ; then 
  1056.   echo shar: Will not clobber existing file \"'common.h'\"
  1057. else
  1058. echo shar: Extracting \"'common.h'\" \(26986 characters\)
  1059. sed "s/^X//" >'common.h' <<'END_OF_FILE'
  1060. X/* $Id: common.h,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  1061. X * 
  1062. X * $Log: common.h,v $
  1063. X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  1064. X * Patchlevel 2 changes
  1065. X *
  1066. X * Revision 4.4  1991/09/09  20:18:23  sob
  1067. X * release 4.4
  1068. X *
  1069. X *
  1070. X *
  1071. X */
  1072. X/* This software is Copyright 1991 by Stan Barber. 
  1073. X *
  1074. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  1075. X * use this software as long as: there is no monetary profit gained
  1076. X * specifically from the use or reproduction of this software, it is not
  1077. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  1078. X * included prominently in any copy made. 
  1079. X *
  1080. X * The author make no claims as to the fitness or correctness of this software
  1081. X * for any use whatsoever, and it is provided as is. Any use of this software
  1082. X * is at the user's own risk. 
  1083. X */
  1084. X#include <stdio.h>
  1085. X#include <sys/types.h>
  1086. X#include <sys/stat.h>
  1087. X#include <ctype.h>
  1088. X#include "config.h"    /* generated by installation script */
  1089. X#ifdef WHOAMI
  1090. X#    include <whoami.h>
  1091. X#endif
  1092. X#ifndef isalnum
  1093. X#   define isalnum(c) (isalpha(c) || isdigit(c))
  1094. X#endif
  1095. X
  1096. X#include <errno.h>
  1097. X#include <signal.h>
  1098. X#ifdef IOCTL
  1099. X#include <sys/ioctl.h>
  1100. X#endif
  1101. X#ifdef SUNOS4
  1102. X# ifdef sparc        /* needed to support vfork call on sparc machines */
  1103. X#  include <vfork.h>
  1104. X# endif
  1105. X#endif
  1106. X
  1107. X#ifdef FCNTL
  1108. X#   include <fcntl.h>
  1109. X#endif
  1110. X
  1111. X#ifdef TERMIO
  1112. X#   include <termio.h>
  1113. X#else
  1114. X# ifdef TERMIOS
  1115. X#   include <termios.h>
  1116. X# else
  1117. X#   include <sgtty.h>
  1118. X# endif
  1119. X#endif
  1120. X
  1121. X#ifdef GETPWENT
  1122. X#   include <pwd.h>
  1123. X#endif
  1124. X
  1125. X#ifdef PTEM
  1126. X#include <sys/stream.h>
  1127. X#include <sys/ptem.h>
  1128. X#endif
  1129. X
  1130. X#define BITSPERBYTE 8
  1131. X#ifdef pdp11
  1132. X#define LBUFLEN 512    /* line buffer length */
  1133. X#else
  1134. X#define LBUFLEN 1024    /* line buffer length */
  1135. X#endif
  1136. X            /* (don't worry, .newsrc lines can exceed this) */
  1137. X#ifdef pdp11
  1138. X#   define CBUFLEN 256    /* command buffer length */
  1139. X#   define PUSHSIZE 128
  1140. X#else
  1141. X#   define CBUFLEN 512    /* command buffer length */
  1142. X#   define PUSHSIZE 256
  1143. X#endif
  1144. X#ifdef pdp11
  1145. X#   define MAXFILENAME 128
  1146. X#else
  1147. X#   define MAXFILENAME 512
  1148. X#endif
  1149. X#define LONGKEY 15    /* longest keyword: currently "posting-version" */
  1150. X#define FINISHCMD 0177
  1151. X
  1152. X/* some handy defs */
  1153. X
  1154. X#define bool char
  1155. X#define bool_int int
  1156. X#define char_int int
  1157. X#ifndef TRUE
  1158. X#define TRUE (1)
  1159. X#endif
  1160. X#ifndef FALSE
  1161. X#define FALSE (0)
  1162. X#endif
  1163. X#define Null(t) ((t)0)
  1164. X#define Nullch Null(char *)
  1165. X#define Nullfp Null(FILE *)
  1166. X
  1167. X#define Ctl(ch) (ch & 037)
  1168. X
  1169. X#define strNE(s1,s2) (strcmp(s1,s2))
  1170. X#define strEQ(s1,s2) (!strcmp(s1,s2))
  1171. X#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
  1172. X#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
  1173. X
  1174. X/* Things we can figure out ourselves */
  1175. X
  1176. X#ifdef SIGTSTP
  1177. X#   define BERKELEY     /* include job control signals? */
  1178. X#endif
  1179. X
  1180. X#ifdef FIONREAD
  1181. X#   define PENDING
  1182. X#else
  1183. X#   ifdef O_NDELAY
  1184. X#    define PENDING
  1185. X#   endif
  1186. X#endif
  1187. X
  1188. X#ifdef EUNICE
  1189. X#   define LINKART        /* add 1 level of possible indirection */
  1190. X#   define UNLINK(victim) while (!unlink(victim))
  1191. X#else
  1192. X#   define UNLINK(victim) unlink(victim)
  1193. X#endif
  1194. X
  1195. X/* Valid substitutions for strings marked with % comment are:
  1196. X *    %a    Current article number
  1197. X *    %A    Full name of current article (%P/%c/%a)
  1198. X *        (if LINKART defined, is the name of the real article)
  1199. X *    %b    Destination of a save command, a mailbox or command
  1200. X *    %B    The byte offset to the beginning of the article for saves
  1201. X *        with or without the header
  1202. X *    %c    Current newsgroup, directory form
  1203. X *    %C    Current newsgroup, dot form
  1204. X *    %d    %P/%c
  1205. X *    %D    Old Distribution: line
  1206. X *    %e    Extract program
  1207. X *    %E    Extract destination directory
  1208. X *    %f    Old From: line or Reply-To: line
  1209. X *    %F    Newsgroups to followup to from Newsgroups: and Followup-To:
  1210. X *    %h    Name of header file to pass to mail or news poster
  1211. X *    %H    Host name (yours)
  1212. X *    %i    Old Message-I.D.: line, with <>
  1213. X *    %I    Inclusion indicator
  1214. X *    %l    News administrator login name
  1215. X *    %L    Login name (yours)
  1216. X *    %M    Number of articles marked with M
  1217. X *    %n    Newsgroups from source article
  1218. X *    %N    Full name (yours)
  1219. X *    %o    Organization (yours)
  1220. X *    %O    Original working directory (where you ran rn from)
  1221. X *    %p    Your private news directory (-d switch)
  1222. X *    %P    Public news spool directory (SPOOLDIR)
  1223. X *    %r    Last reference (parent article id)
  1224. X *    %R    New references list
  1225. X *    %s    Subject, with all Re's and (nf)'s stripped off
  1226. X *    %S    Subject, with one Re stripped off
  1227. X *    %t    New To: line derived from From: and Reply-To (Internet always)
  1228. X *    %T    New To: line derived from Path:
  1229. X *    %u    Number of unread articles
  1230. X *    %U    Number of unread articles disregarding current article
  1231. X *    %v    Number of unselected articles disregarding current article
  1232. X *    %w    Mthreads' tmp directory
  1233. X *    %W    The thread directory root
  1234. X *    %x    News library directory, usually /usr/lib/news
  1235. X *    %X    Rn library directory, usually %x/rn
  1236. X *    %z    Size of current article in bytes.
  1237. X *    %Z    Number of selected threads.
  1238. X *    %~    Home directory
  1239. X *    %.    Directory containing . files
  1240. X *    %#    count of articles saved in current command (from 1 to n)
  1241. X *    %$    current process number
  1242. X *    %{name} Environment variable "name".  %{name-default} form allowed.
  1243. X *    %[name]    Header line beginning with "Name: ", without "Name: " 
  1244. X *    %"prompt"
  1245. X *        Print prompt and insert what is typed.
  1246. X *    %`command`
  1247. X *        Insert output of command.
  1248. X *    %(test_text=pattern?if_text:else_text)
  1249. X *        Substitute if_text if test_text matches pattern, otherwise
  1250. X *        substitute else_text.  Use != for negated match.
  1251. X *        % substitutions are done on test_text, if_text, and else_text.
  1252. X *        (Note: %() only works if CONDSUB defined.)
  1253. X *    %digit    Substitute the text matched by the nth bracket in the last
  1254. X *        pattern that had brackets.  %0 matches the last bracket
  1255. X *        matched, in case you had alternatives.
  1256. X *
  1257. X *    Put ^ in the middle to capitalize the first letter: %^C = Net.jokes
  1258. X *    Put _ in the middle to capitalize last component: %_c = net/Jokes
  1259. X *
  1260. X *    ~ interpretation in filename expansion happens after % expansion, so
  1261. X *    you could put ~%{NEWSLOGNAME-news} and it will expand correctly.
  1262. X */
  1263. X
  1264. X/* *** System Dependent Stuff *** */
  1265. X
  1266. X/* NOTE: many of these are defined in the config.h file */
  1267. X
  1268. X/* name of organization */
  1269. X#ifndef ORGNAME
  1270. X#   define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota"
  1271. X#endif
  1272. X
  1273. X#ifndef MBOXCHAR
  1274. X#   define MBOXCHAR 'F'    /* how to recognize a mailbox by 1st char */
  1275. X#endif
  1276. X
  1277. X#ifndef ROOTID
  1278. X#   define ROOTID 0        /* uid of superuser */
  1279. X#endif
  1280. X
  1281. X#ifdef NORMSIG
  1282. X#   define sigset signal
  1283. X#   define sigignore(sig) signal(sig,SIG_IGN)
  1284. X#endif
  1285. X
  1286. X#ifndef LOGDIRFIELD
  1287. X#   define LOGDIRFIELD 6        /* Which field (origin 1) is the */
  1288. X                    /* login directory in /etc/passwd? */
  1289. X                    /* (If it is not kept in passwd, */
  1290. X                    /* but getpwnam() returns it, */
  1291. X                    /* define the symbol GETPWENT) */
  1292. X#endif
  1293. X#ifndef GCOSFIELD
  1294. X#   define GCOSFIELD 5
  1295. X#endif
  1296. X
  1297. X#ifndef NEGCHAR
  1298. X#   define NEGCHAR '!'
  1299. X#endif
  1300. X
  1301. X/* Space conservation section */
  1302. X
  1303. X/* To save D space, cut down size of NGMAX and  VARYSIZE. */
  1304. X#define NGMAX 100    /* number of newsgroups allowed on command line */
  1305. X            /* undefine ONLY symbol to disable "only" feature */
  1306. X#define VARYSIZE 256    /* this makes a block 1024 bytes long in DECville */
  1307. X            /* (used by virtual array routines) */
  1308. X
  1309. X/* Undefine any of the following features to save both I and D space */
  1310. X/* In general, earlier ones are easier to get along without */
  1311. X/* Pdp11's without split I and D may have to undefine them all */
  1312. X#define DEBUGGING    /* include debugging code */
  1313. X#define USETHREADS    /* Add article-thread following */
  1314. X#define CUSTOMLINES    /* include code for HIDELINE and PAGESTOP */
  1315. X#define PUSHBACK    /* macros and keymaps using pushback buffer */
  1316. X#define SPEEDOVERMEM    /* use more memory to run faster */
  1317. X#define WORDERASE    /* enable ^W to erase a word */
  1318. X#define MAILCALL    /* check periodically for mail */
  1319. X#define CLEAREOL    /* use clear to end-of-line instead of clear screen */
  1320. X#define NOFIREWORKS    /* keep whole screen from flashing on certain */
  1321. X            /* terminals such as older Televideos */
  1322. X#define VERIFY        /* echo the command they just typed */
  1323. X#define HASHNG        /* hash newsgroup lines for fast lookup-- */
  1324. X            /* linear search used if not defined */
  1325. X#define CONDSUB        /* allow %(cond?text:text) */
  1326. X#define BACKTICK    /* allow %`command` */
  1327. X#define PROMPTTTY    /* allow %"prompt" */
  1328. X#define ULSMARTS    /* catch _^H in text and do underlining */
  1329. X#define TERMMOD        /* allow terminal type modifier on switches */
  1330. X#define BAUDMOD        /* allow baudrate modifier on switches */
  1331. X#define GETLOGIN    /* use getlogin() routine as backup to environment */
  1332. X            /* variables USER or LOGNAME */
  1333. X#define ORGFILE        /* if organization begins with /, look up in file */
  1334. X#define TILDENAME    /* allow ~logname expansion */
  1335. X#define SETENV        /* allow command line environment variable setting */
  1336. X#define MAKEDIR        /* use our makedir() instead of shell script */
  1337. X#define MEMHELP        /* keep help messages in memory */
  1338. X#define VERBOSE        /* compile in more informative messages */
  1339. X#define TERSE        /* compile in shorter messages */
  1340. X            /* (Note: both VERBOSE and TERSE can be defined; -t
  1341. X             * sets terse mode.  One or the other MUST be defined.
  1342. X             */
  1343. X#ifndef pdp11
  1344. X#   define CACHESUBJ    /* cache subject lines in memory */
  1345. X            /* without this ^N still works but runs really slow */
  1346. X            /* but you save lots and lots of D space */
  1347. X#   define CACHEFIRST    /* keep absolute first article numbers in memory */
  1348. X            /* cost: about 2k */
  1349. X#endif
  1350. X#define ROTATION    /* enable x, X and ^X commands to work */
  1351. X#define DELBOGUS    /* ask if bogus newsgroups should be deleted */
  1352. X#define RELOCATE    /* allow newsgroup rearranging */
  1353. X#define ESCSUBS        /* escape substitutions in multi-character commands */
  1354. X#define DELAYMARK    /* allow articles to be temporarily marked as read */
  1355. X            /* until exit from current newsgroup or Y command */
  1356. X#undef MCHASE        /* unmark xrefed articles on m or M */
  1357. X#define MUNGHEADER    /* allow alternate header formatting via */
  1358. X            /* environment variable ALTHEADER (not impl) */
  1359. X#define ASYNC_PARSE    /* allow parsing headers asyncronously to reading */
  1360. X            /* used by MCHASE and MUNGHEADER */
  1361. X#define FINDNEWNG    /* check for new newsgroups on startup */
  1362. X#define FASTNEW        /* do optimizations on FINDNEWNG for faster startup */
  1363. X            /* (this optimization can make occasional mistakes */
  1364. X            /* if a group is removed and another group of the */
  1365. X            /* same length is added, and if no softpointers are */
  1366. X            /* affected by said change.) */
  1367. X#define INNERSEARCH    /* search command 'g' with article */
  1368. X#define CATCHUP        /* catchup command at newsgroup level */
  1369. X#define NGSEARCH    /* newsgroup pattern matching */
  1370. X#define ONLY        /* newsgroup restrictions by pattern */
  1371. X#define KILLFILES    /* automatic article killer files */
  1372. X#define ARTSEARCH    /* pattern searches among articles */
  1373. X            /* /, ?, ^N, ^P, k, K */
  1374. X
  1375. X/* some dependencies among options */
  1376. X
  1377. X#ifndef ARTSEARCH
  1378. X#   undef KILLFILES
  1379. X#   undef INNERSEARCH
  1380. X#   undef CACHESUBJ
  1381. X#endif
  1382. X
  1383. X#ifndef DELAYMARK
  1384. X#   ifndef MCHASE
  1385. X#    ifndef MUNGHEADER
  1386. X#        undef ASYNC_PARSE
  1387. X#    endif
  1388. X#   endif
  1389. X#endif
  1390. X
  1391. X#ifndef SETUIDGID
  1392. X#   define eaccess access
  1393. X#endif
  1394. X
  1395. X#ifdef ONLY                /* idiot lint doesn't grok #if */
  1396. X#   define NGSORONLY
  1397. X#else
  1398. X#   ifdef NGSEARCH
  1399. X#    define NGSORONLY
  1400. X#   endif
  1401. X#endif
  1402. X
  1403. X#ifdef VERBOSE
  1404. X#   ifdef TERSE
  1405. X#    define IF(c) if (c)
  1406. X#    define ELSE else
  1407. X#   else
  1408. X#    define IF(c)
  1409. X#    define ELSE
  1410. X#   endif
  1411. X#else /* !VERBOSE */
  1412. X#   ifndef TERSE
  1413. X#    define TERSE
  1414. X#   endif
  1415. X#   define IF(c) "IF" outside of VERBOSE???
  1416. X#   define ELSE "ELSE" outside of VERBOSE???
  1417. X#endif
  1418. X
  1419. X#ifdef DEBUGGING
  1420. X#   define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\n", __FILE__, __LINE__);sig_catcher(0);}}
  1421. X#else
  1422. X#   define assert(ex) ;
  1423. X#endif
  1424. X
  1425. X#ifdef SPEEDOVERMEM
  1426. X#   define OFFSET(x) (x)
  1427. X#else
  1428. X#   define OFFSET(x) ((x)-absfirst)
  1429. X#endif
  1430. X
  1431. X/* If you're strapped for space use the help messages in shell scripts */
  1432. X/* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */
  1433. X#ifdef MEMHELP  /* undef MEMHELP above to get them all as sh scripts */
  1434. X#   undef NGHELP
  1435. X#   undef ARTHELP
  1436. X#   undef PAGERHELP
  1437. X#   undef SUBSHELP
  1438. X#else
  1439. X#   ifndef NGHELP            /* % and ~ */
  1440. X#    define NGHELP "%X/ng.help"
  1441. X#   endif
  1442. X#   ifndef ARTHELP            /* % and ~ */
  1443. X#    define ARTHELP "%X/art.help"
  1444. X#   endif
  1445. X#   ifndef PAGERHELP        /* % and ~ */
  1446. X#    define PAGERHELP "%X/pager.help"
  1447. X#   endif
  1448. X#   ifndef SUBSHELP        /* % and ~ */
  1449. X#    define SUBSHELP "%X/subs.help"
  1450. X#   endif
  1451. X#endif
  1452. X
  1453. X#ifdef CLEAREOL
  1454. X#   define TCSIZE 512    /* capacity for termcap strings */
  1455. X#else
  1456. X#   ifdef pdp11
  1457. X#    define TCSIZE 256    /* capacity for termcap strings */
  1458. X#   else
  1459. X#    define TCSIZE 512    /* capacity for termcap srings */
  1460. X#   endif
  1461. X#endif
  1462. X
  1463. X/* Additional ideas:
  1464. X *    Make the do_newsgroup() routine a separate process.
  1465. X *    Keep .newsrc on disk instead of in memory.
  1466. X *    Overlays, if you have them.
  1467. X *    Get a bigger machine.
  1468. X */
  1469. X
  1470. X/* End of Space Conservation Section */
  1471. X
  1472. X/* More System Dependencies */
  1473. X
  1474. X/* news library */
  1475. X#ifndef LIB        /* ~ and %l only ("~%l" is permissable) */
  1476. X#   define LIB "/usr/lib/news"
  1477. X#endif
  1478. X
  1479. X/* path to private executables */
  1480. X#ifndef RNLIB        /* ~, %x and %l only */
  1481. X#   define RNLIB "%x/trn"
  1482. X#endif
  1483. X
  1484. X/* system-wide RNINIT switches */
  1485. X#ifndef GLOBINIT
  1486. X#   define GLOBINIT "%X/INIT"
  1487. X#endif
  1488. X
  1489. X/* where to find news files */
  1490. X#ifndef SPOOL            /* % and ~ */
  1491. X#   define SPOOL "/usr/spool/news"
  1492. X#endif
  1493. X
  1494. X#ifdef USETHREADS
  1495. X# ifdef THREAD_DIR
  1496. X#   ifdef LONG_THREAD_NAMES
  1497. X#    undef SUFFIX
  1498. X#   else
  1499. X#     ifndef SUFFIX
  1500. X#    define SUFFIX ".th"
  1501. X#     endif
  1502. X#   endif
  1503. X# else
  1504. X#   define THREAD_DIR    SPOOL
  1505. X#   ifndef SUFFIX
  1506. X#     define SUFFIX    "/.thread"
  1507. X#   endif
  1508. X#   undef LONG_THREAD_NAMES
  1509. X# endif
  1510. X# ifndef NEW_THREAD
  1511. X#   define NEW_THREAD ".new"
  1512. X# endif
  1513. X#endif
  1514. X
  1515. X/* default characters to use in the selection menu */
  1516. X#ifndef SELECTCHARS
  1517. X#   define SELECTCHARS "abcdefgijlorstuvwxz1234567890"
  1518. X#endif
  1519. X
  1520. X/* file containing list of active newsgroups and max article numbers */
  1521. X#ifndef ACTIVE            /* % and ~ */
  1522. X#   define ACTIVE "%x/active"
  1523. X#endif
  1524. X#ifdef SERVER
  1525. X#   ifndef ACTIVE1
  1526. X#    define ACTIVE1 "%w/active1"
  1527. X#   endif
  1528. X#endif
  1529. X#ifndef ACTIVE2
  1530. X#   define ACTIVE2 "%w/active2"
  1531. X#endif
  1532. X#ifndef DBINIT
  1533. X#   define DBINIT "%W/db.init"
  1534. X#endif
  1535. X#ifndef MTPRELOCK
  1536. X#   define MTPRELOCK "%w/LOCK"
  1537. X#endif
  1538. X#ifndef MTLOCK
  1539. X#   define MTLOCK "%w/LOCKmthreads"
  1540. X#endif
  1541. X#ifndef MTDLOCK
  1542. X#   define MTDLOCK "%w/LOCKmtdaemon"
  1543. X#endif
  1544. X#ifndef MTLOG
  1545. X#   define MTLOG "%w/mt.log"
  1546. X#endif
  1547. X
  1548. X#if !defined(SERVER) && defined(XTHREAD)
  1549. X#   undef XTHREAD
  1550. X#endif
  1551. X
  1552. X/* location of history file */
  1553. X#ifndef ARTFILE            /* % and ~ */
  1554. X#    define ARTFILE "%x/history"
  1555. X#endif
  1556. X
  1557. X/* command to setup a new .newsrc */
  1558. X#ifndef NEWSETUP        /* % and ~ */
  1559. X#   define NEWSETUP "newsetup"
  1560. X#endif
  1561. X
  1562. X/* command to display a list of un-subscribed-to newsgroups */
  1563. X#ifndef NEWSGROUPS        /* % and ~ */
  1564. X#   define NEWSGROUPS "newsgroups"
  1565. X#endif
  1566. X
  1567. X/* preferred shell for use in doshell routine */
  1568. X/*  ksh or sh would be okay here */
  1569. X#ifndef PREFSHELL
  1570. X#   define PREFSHELL "/bin/csh"
  1571. X#endif
  1572. X
  1573. X/* path to fastest starting shell */
  1574. X#ifndef SH
  1575. X#   define SH "/bin/sh"
  1576. X#endif
  1577. X
  1578. X/* default unshar'ing program */
  1579. X#ifndef UNSHAR
  1580. X#   define UNSHAR "/bin/sh"
  1581. X#endif
  1582. X
  1583. X/* path to default editor */
  1584. X#ifndef DEFEDITOR
  1585. X#   define DEFEDITOR "/usr/ucb/vi"
  1586. X#endif
  1587. X
  1588. X/* location of macro file */
  1589. X#ifndef RNMACRO
  1590. X#   ifdef PUSHBACK
  1591. X#    define RNMACRO "%./.rnmac"
  1592. X#   endif
  1593. X#endif
  1594. X
  1595. X/* location of full name */
  1596. X#ifndef FULLNAMEFILE
  1597. X#   ifndef PASSNAMES
  1598. X#    define FULLNAMEFILE "%./.fullname"
  1599. X#   endif
  1600. X#endif
  1601. X
  1602. X/* virtual array file name template */
  1603. X#ifndef VARYNAME        /* % and ~ */
  1604. X#   define VARYNAME "/tmp/rnvary.%$"
  1605. X#endif
  1606. X
  1607. X/* where to compile a new newsgroup list */
  1608. X#ifndef RNEWNAME
  1609. X#   define RNEWNAME "/tmp/rnew.%$"
  1610. X#endif
  1611. X
  1612. X/* file to pass header to followup article poster */
  1613. X#ifndef HEADNAME        /* % and ~ */
  1614. X#   define HEADNAME "%./.rnhead"
  1615. X/* or alternately #define HEADNAME "/tmp/rnhead.%$" */
  1616. X#endif
  1617. X
  1618. X#ifndef MAKEDIR
  1619. X/* shell script to make n-deep subdirectories */
  1620. X#   ifndef DIRMAKER        /* % and ~ */
  1621. X#    define DIRMAKER "%X/makedir"
  1622. X#   endif
  1623. X#endif
  1624. X
  1625. X/* location of newsrc file */
  1626. X#ifndef RCNAME        /* % and ~ */
  1627. X#   define RCNAME "%./.newsrc"
  1628. X#endif
  1629. X
  1630. X/* temporary newsrc file in case we crash while writing out */
  1631. X#ifndef RCTNAME        /* % and ~ */
  1632. X#   define RCTNAME "%./.newnewsrc"
  1633. X#endif
  1634. X
  1635. X/* newsrc file at the beginning of this session */
  1636. X#ifndef RCBNAME        /* % and ~ */
  1637. X#   define RCBNAME "%./.oldnewsrc"
  1638. X#endif
  1639. X
  1640. X/* if existent, contains process number of current or crashed rn */
  1641. X#ifndef LOCKNAME        /* % and ~ */
  1642. X#   define LOCKNAME "%./.rnlock"
  1643. X#endif
  1644. X
  1645. X/* information from last invocation of rn */
  1646. X#ifndef LASTNAME        /* % and ~ */
  1647. X#   define LASTNAME "%./.rnlast"
  1648. X#endif
  1649. X
  1650. X/* file with soft pointers into the active file */
  1651. X#ifndef SOFTNAME        /* % and ~ */
  1652. X#   define SOFTNAME "%./.rnsoft"
  1653. X#endif
  1654. X
  1655. X/* list of article numbers to mark as unread later (see M and Y cmmands) */
  1656. X#ifndef RNDELNAME        /* % and ~ */
  1657. X#   define RNDELNAME "%./.rndelay"
  1658. X#endif
  1659. X
  1660. X/* a motd-like file for rn */
  1661. X#ifndef NEWSNEWSNAME        /* % and ~ */
  1662. X#   define NEWSNEWSNAME "%X/newsnews"
  1663. X#endif
  1664. X
  1665. X/* command to send a reply */
  1666. X#ifndef MAILPOSTER        /* % and ~ */
  1667. X#   define MAILPOSTER "Rnmail -h %h"
  1668. X#endif
  1669. X
  1670. X#ifdef INTERNET
  1671. X#   ifndef MAILHEADER        /* % */
  1672. X#    ifdef CONDSUB
  1673. X#        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  1674. X#    else
  1675. X#        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  1676. X#    endif
  1677. X#   endif
  1678. X#else
  1679. X#   ifndef MAILHEADER        /* % */
  1680. X#    ifdef CONDSUB
  1681. X#        define MAILHEADER "To: %T\nSubject: %(%i=^$?:Re: %S\nNewsgroups: %n\nIn-Reply-To: %i)\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  1682. X#    else
  1683. X#        define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  1684. X#    endif
  1685. X#   endif
  1686. X#endif
  1687. X
  1688. X#ifndef YOUSAID            /* % */
  1689. X#   define YOUSAID "In article %i you write:"
  1690. X#endif
  1691. X
  1692. X/* command to submit a followup article */
  1693. X#ifndef NEWSPOSTER        /* % and ~ */
  1694. X#   define NEWSPOSTER "Pnews -h %h"
  1695. X#endif
  1696. X
  1697. X#ifndef NEWSHEADER        /* % */
  1698. X#   ifdef CONDSUB
  1699. X#ifdef INTERNET
  1700. X#    define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
  1701. X#else
  1702. X#    define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
  1703. X#endif
  1704. X#   else
  1705. X#    ifdef INTERNET
  1706. X#        define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
  1707. X#    else
  1708. X#        define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
  1709. X#    endif
  1710. X#   endif
  1711. X#endif
  1712. X
  1713. X#ifndef ATTRIBUTION        /* % */
  1714. X#   define ATTRIBUTION "In article %i %f writes:"
  1715. X#endif
  1716. X
  1717. X#ifndef PIPESAVER        /* % */
  1718. X#   ifdef CONDSUB
  1719. X#       ifdef SERVER
  1720. X#               define PIPESAVER "%(%B=^0$?<%P/rrn%a.%$:tail +%Bc %P/rrn%a.%$ |) %b"
  1721. X#       else
  1722. X#        define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
  1723. X#    endif
  1724. X#   else
  1725. X#       ifdef SERVER
  1726. X#               define PIPESAVER "tail +%Bc %P/rrn%a.%$ | %b"
  1727. X#       else
  1728. X#        define PIPESAVER "tail +%Bc %A | %b"
  1729. X#    endif
  1730. X#   endif
  1731. X#endif
  1732. X
  1733. X#ifndef EXSAVER
  1734. X#    ifdef SERVER
  1735. X#    define EXSAVER "tail +%Bc %P/rrn%a.%$ | %e"
  1736. X#    else
  1737. X#    define EXSAVER "tail +%Bc %A | %e"
  1738. X#    endif
  1739. X#endif
  1740. X
  1741. X#ifndef NORMSAVER        /* % and ~ */
  1742. X#    ifdef SERVER
  1743. X#    define NORMSAVER "%X/norm.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\""
  1744. X#    else
  1745. X#       define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
  1746. X#    endif
  1747. X#endif
  1748. X
  1749. X#ifndef MBOXSAVER        /* % and ~ */
  1750. X#   ifdef MININACT        /* 2.10.2 site? */
  1751. X#       ifdef SERVER
  1752. X#           define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %`date`\""
  1753. X#       else
  1754. X#        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
  1755. X#    endif
  1756. X#   else
  1757. X#    ifdef CONDSUB
  1758. X#           ifdef SERVER
  1759. X#               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
  1760. X#           else
  1761. X#            define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
  1762. X#        endif
  1763. X                    /* header munging with a vengeance */
  1764. X#    else
  1765. X#           ifdef SERVER
  1766. X#               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %[posted]\""
  1767. X#           else
  1768. X#            define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
  1769. X#        endif
  1770. X#    endif
  1771. X#   endif
  1772. X#endif
  1773. X
  1774. X#ifdef MKDIRS
  1775. X
  1776. X#   ifndef SAVEDIR            /* % and ~ */
  1777. X#    define SAVEDIR "%p/%c"
  1778. X#   endif
  1779. X#   ifndef SAVENAME        /* % */
  1780. X#    define SAVENAME "%a"
  1781. X#   endif
  1782. X
  1783. X#else
  1784. X
  1785. X#   ifndef SAVEDIR            /* % and ~ */
  1786. X#    define SAVEDIR "%p"
  1787. X#   endif
  1788. X#   ifndef SAVENAME        /* % */
  1789. X#    define SAVENAME "%^C"
  1790. X#   endif
  1791. X
  1792. X#endif
  1793. X
  1794. X#ifndef KILLGLOBAL        /* % and ~ */
  1795. X#   define KILLGLOBAL "%p/KILL"
  1796. X#endif
  1797. X
  1798. X#ifndef KILLLOCAL        /* % and ~ */
  1799. X#   define KILLLOCAL "%p/%c/KILL"
  1800. X#endif
  1801. X
  1802. X/* how to cancel an article */
  1803. X#ifndef CANCEL
  1804. X#   ifdef MININACT            /* 2.10.2 ? */
  1805. X#    define CANCEL "%x/inews -h < %h"
  1806. X#   else
  1807. X#    define CANCEL "inews -h < %h"
  1808. X#   endif
  1809. X#endif
  1810. X
  1811. X/* how to cancel an article, continued */
  1812. X#ifndef CANCELHEADER
  1813. X#ifdef INTERNET
  1814. X#   define CANCELHEADER "From: %L@%H (%N)\nNewsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nDistribution: %D\nOrganization: %o\n\n%i was cancelled from within trn.\n"
  1815. X#else
  1816. X#   define CANCELHEADER "From:%L@%H.UUCP (%N)\nNewsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nDistribution: %D\nOrganization: %o\n\n%i was cancelled from within trn.\n"
  1817. X#endif
  1818. X#endif
  1819. X
  1820. X/* how to supersede an article */
  1821. X#ifndef SUPERSEDEHEADER
  1822. X#ifdef INTERNET
  1823. X#   define SUPERSEDEHEADER "From: %L@%H (%N)\nNewsgroups: %n\nSupersedes: %i\nSubject: %S\nDistribution: %D\nOrganization: %o\n"
  1824. X#else
  1825. X#   define SUPERSEDEHEADER "From:%L@%H.UUCP (%N)\nNewsgroups: %n\nSupersedes: %i\nSubject: %S\nDistribution: %D\nOrganization: %o\n"
  1826. X#endif
  1827. X#endif
  1828. X
  1829. X#ifndef LOCALTIMEFMT
  1830. X#   define LOCALTIMEFMT "%a %b %d %X %Z %Y"
  1831. X#endif
  1832. X
  1833. X/* where to find the mail file */
  1834. X#ifndef MAILFILE
  1835. X#   define MAILFILE "/usr/spool/mail/%L"
  1836. X#endif
  1837. X
  1838. X/* how to open binary format files */
  1839. X#ifndef FOPEN_RB
  1840. X#   define FOPEN_RB "r"
  1841. X#endif
  1842. X#ifndef FOPEN_WB
  1843. X#   define FOPEN_WB "w"
  1844. X#endif
  1845. X
  1846. X/* what to do with ansi prototypes -- '()' == ignore, 'x' == use */
  1847. X#ifndef ANSI
  1848. X#   ifdef __STDC__
  1849. X#    define ANSI(x) x
  1850. X#   else
  1851. X#    define ANSI(x) ()
  1852. X#   endif
  1853. X#endif
  1854. X
  1855. X/* how many characters is a newline in a text file? */
  1856. X#ifndef NL_SIZE
  1857. X#   define NL_SIZE 1
  1858. X#endif
  1859. X
  1860. X/* some important types */
  1861. X
  1862. typedef int        NG_NUM;        /* newsgroup number */
  1863. typedef long        ART_NUM;    /* article number */
  1864. X#ifdef pdp11
  1865. X    typedef short    ART_UNREAD;    /* ordinarily this should be long */
  1866. X                    /* like ART_NUM, but assuming that */
  1867. X                    /* we stay less than 32767 articles */
  1868. X                    /* behind saves a lot of space. */
  1869. X                    /* NOTE: do not make unsigned. */
  1870. X#else
  1871. X    typedef long    ART_UNREAD;
  1872. X#endif
  1873. X#ifdef SERVER
  1874. typedef int        ART_PART;    /* for passing to nntpopen() */
  1875. X#endif
  1876. typedef long        ART_POS;    /* char position in article file */
  1877. typedef int        ART_LINE;    /* line position in article file */
  1878. typedef long        ACT_POS;    /* char position in active file */
  1879. typedef unsigned int    MEM_SIZE;    /* for passing to malloc */
  1880. X
  1881. X
  1882. X/* *** end of the machine dependent stuff *** */
  1883. X
  1884. X/* GLOBAL THINGS */
  1885. X
  1886. X/* file statistics area */
  1887. X
  1888. XEXT struct stat filestat;
  1889. X
  1890. X/* various things of type char */
  1891. X
  1892. char    *index();
  1893. char    *rindex();
  1894. char    *getenv();
  1895. char    *strcat();
  1896. char    *strcpy();
  1897. X
  1898. XEXT char buf[LBUFLEN+1];    /* general purpose line buffer */
  1899. XEXT char cmd_buf[CBUFLEN];    /* buffer for formatting system commands */
  1900. XEXT char *indstr INIT(">");    /* indent for old article embedded in followup */
  1901. X
  1902. XEXT char *cwd INIT(Nullch);        /* current working directory */
  1903. XEXT char *dfltcmd INIT(Nullch);    /* 1st char is default command */
  1904. X
  1905. X/* switches */
  1906. X
  1907. X#ifdef DEBUGGING
  1908. X    EXT int debug INIT(0);                /* -D */
  1909. X#   define DEB_NNTP 16 
  1910. X#   define DEB_INNERSRCH 32 
  1911. X#   define DEB_FILEXP 64 
  1912. X#   define DEB_HASH 128
  1913. X#   define DEB_XREF_MARKER 256
  1914. X#   define DEB_CTLAREA_BITMAP 512
  1915. X#   define DEB_SOFT_POINTERS 1024
  1916. X#   define DEB_NEWSRC_LINE 2048
  1917. X#   define DEB_SEARCH_AHEAD 4096
  1918. X#   define DEB_CHECKPOINTING 8192
  1919. X#   define DEB_FEED_XREF 16384
  1920. X#endif
  1921. X
  1922. X#ifdef ARTSEARCH
  1923. X    EXT int scanon INIT(0);                /* -S */
  1924. X#endif
  1925. X
  1926. X#ifdef USETHREADS
  1927. X    EXT bool use_threads INIT(THREAD_INIT);        /* -x */
  1928. X    EXT int max_tree_lines INIT(6);
  1929. X    EXT char select_order[4] INIT("lsm");
  1930. X    EXT int select_on INIT(SELECT_INIT);        /* -X */
  1931. X    EXT char end_select INIT('Z');
  1932. X    EXT char page_select INIT('>');
  1933. X#endif
  1934. X
  1935. XEXT bool mbox_always INIT(FALSE);            /* -M */
  1936. XEXT bool norm_always INIT(FALSE);            /* -N */
  1937. XEXT bool thread_always INIT(FALSE);            /* -a */
  1938. XEXT bool olden_days INIT(FALSE);            /* -o */
  1939. XEXT bool checkflag INIT(FALSE);            /* -c */
  1940. XEXT bool suppress_cn INIT(FALSE);            /* -s */
  1941. XEXT int countdown INIT(5);    /* how many lines to list before invoking -s */
  1942. XEXT bool muck_up_clear INIT(FALSE);            /* -loco */
  1943. XEXT bool erase_screen INIT(FALSE);            /* -e */
  1944. X#if defined(CLEAREOL) || defined(USETHREADS)
  1945. XEXT bool can_home INIT(FALSE);
  1946. X#endif
  1947. X#ifdef CLEAREOL
  1948. XEXT bool can_home_clear INIT(FALSE);        /* fancy -e */
  1949. X#endif
  1950. XEXT bool findlast INIT(FALSE);            /* -r */
  1951. XEXT bool typeahead INIT(FALSE);            /* -T */
  1952. X#ifdef VERBOSE
  1953. X#   ifdef TERSE
  1954. X    EXT bool verbose INIT(TRUE);            /* +t */
  1955. X#   endif
  1956. X#endif
  1957. X#ifdef VERIFY
  1958. X    EXT bool verify INIT(FALSE);            /* -v */
  1959. X#endif
  1960. X    EXT bool quickstart INIT(FALSE);            /* -q */
  1961. X
  1962. X#define NOMARKING 0
  1963. X#define STANDOUT 1
  1964. X#define UNDERLINE 2
  1965. XEXT int marking INIT(NOMARKING);            /* -m */
  1966. X
  1967. XEXT ART_LINE initlines INIT(0);        /* -i */
  1968. XEXT bool initlines_specified INIT(FALSE);
  1969. X
  1970. X/* miscellania */
  1971. X
  1972. int fseek();
  1973. long atol(), ftell();
  1974. XEXT bool in_ng INIT(FALSE);        /* current state of rn */
  1975. XEXT char mode INIT('i');        /* current state of rn */
  1976. X
  1977. XEXT FILE *tmpfp INIT(Nullfp);    /* scratch fp used for .rnlock, .rnlast, etc. */
  1978. X
  1979. XEXT NG_NUM nextrcline INIT(0);    /* 1st unused slot in rcline array */
  1980. X            /* startup to avoid checking twice in a row */
  1981. X
  1982. extern errno;
  1983. X/* Factored strings */
  1984. X
  1985. XEXT char nullstr[1] INIT("");
  1986. XEXT char sh[] INIT(SH);
  1987. XEXT char defeditor[] INIT(DEFEDITOR);
  1988. XEXT char hforhelp[] INIT("Type h for help.\n");
  1989. X#ifdef STRICTCR
  1990. XEXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
  1991. X#endif
  1992. XEXT char readerr[] INIT("rn read error");
  1993. XEXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
  1994. XEXT char cantopen[] INIT("Can't open %s\n");
  1995. XEXT char cantcreate[] INIT("Can't create %s\n");
  1996. XEXT char cantrecreate[] INIT("Can't recreate %s -- restoring older version.\n");
  1997. X
  1998. X#ifdef VERBOSE
  1999. X    EXT char nocd[] INIT("Can't chdir to directory %s\n");
  2000. X#else
  2001. X    EXT char nocd[] INIT("Can't find %s\n");
  2002. X#endif
  2003. X
  2004. X#ifdef NOLINEBUF
  2005. X#define FLUSH ,fflush(stdout)
  2006. X#else
  2007. X#define FLUSH
  2008. X#endif
  2009. X
  2010. X#ifdef lint
  2011. X#undef FLUSH
  2012. X#define FLUSH
  2013. X#undef putchar
  2014. X#define putchar(c)
  2015. X#endif
  2016. END_OF_FILE
  2017. if test 26986 -ne `wc -c <'common.h'`; then
  2018.     echo shar: \"'common.h'\" unpacked with wrong size!
  2019. fi
  2020. # end of 'common.h'
  2021. fi
  2022. if test -f 'term.c' -a "${1}" != "-c" ; then 
  2023.   echo shar: Will not clobber existing file \"'term.c'\"
  2024. else
  2025. echo shar: Extracting \"'term.c'\" \(26055 characters\)
  2026. sed "s/^X//" >'term.c' <<'END_OF_FILE'
  2027. X/* $Id: term.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  2028. X *
  2029. X * $Log: term.c,v $
  2030. X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  2031. X * Patchlevel 2 changes
  2032. X *
  2033. X * Revision 4.4  1991/09/09  20:27:37  sob
  2034. X * release 4.4
  2035. X *
  2036. X *
  2037. X * 
  2038. X */
  2039. X/* This software is Copyright 1991 by Stan Barber. 
  2040. X *
  2041. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  2042. X * use this software as long as: there is no monetary profit gained
  2043. X * specifically from the use or reproduction of this software, it is not
  2044. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  2045. X * included prominently in any copy made. 
  2046. X *
  2047. X * The author make no claims as to the fitness or correctness of this software
  2048. X * for any use whatsoever, and it is provided as is. Any use of this software
  2049. X * is at the user's own risk. 
  2050. X */
  2051. X
  2052. X#include "EXTERN.h"
  2053. X#include "common.h"
  2054. X#include "util.h"
  2055. X#include "final.h"
  2056. X#include "help.h"
  2057. X#include "cheat.h"
  2058. X#include "intrp.h"
  2059. X#include "INTERN.h"
  2060. X#include "term.h"
  2061. X
  2062. char ERASECH;        /* rubout character */
  2063. char KILLCH;        /* line delete character */
  2064. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  2065. X
  2066. X#ifdef USETHREADS
  2067. int upcost;
  2068. X#endif
  2069. X
  2070. X/* guarantee capability pointer != Nullch */
  2071. X/* (I believe terminfo will ignore the &tmpaddr argument.) */
  2072. X
  2073. X#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  2074. X
  2075. X#ifdef PUSHBACK
  2076. struct keymap {
  2077. X    char km_type[128];
  2078. X    union km_union {
  2079. X    struct keymap *km_km;
  2080. X    char *km_str;
  2081. X    } km_ptr[128];
  2082. X};
  2083. X
  2084. X#define KM_NOTHIN 0
  2085. X#define KM_STRING 1
  2086. X#define KM_KEYMAP 2
  2087. X#define KM_BOGUS 3
  2088. X
  2089. X#define KM_TMASK 3
  2090. X#define KM_GSHIFT 4
  2091. X#define KM_GMASK 7
  2092. X
  2093. typedef struct keymap KEYMAP;
  2094. X
  2095. KEYMAP *topmap INIT(Null(KEYMAP*));
  2096. X
  2097. void mac_init();
  2098. KEYMAP *newkeymap();
  2099. void show_keymap();
  2100. void pushstring();
  2101. X#endif
  2102. X
  2103. void line_col_calcs();
  2104. X
  2105. X/* terminal initialization */
  2106. X
  2107. void
  2108. term_init()
  2109. X{
  2110. X    savetty();                /* remember current tty state */
  2111. X
  2112. X#ifdef TERMIO
  2113. X    outspeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  2114. X    ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  2115. X    KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  2116. X    if (GT = ((_tty.c_oflag & TABDLY) != TAB3))
  2117. X    /* we have tabs, so that's OK */;
  2118. X    else
  2119. X    _tty.c_oflag &= ~TAB3;    /* turn off kernel tabbing -- done in rn */
  2120. X#else /* !TERMIO */
  2121. X# ifdef TERMIOS
  2122. X    outspeed = cfgetospeed(&_tty);    /* for tputs() (output) */
  2123. X    ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  2124. X    KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  2125. X/*    _tty.c_oflag &= ~OXTABS;        /* turn off kernel tabbing-done in rn */
  2126. X# else /* !TERMIOS */
  2127. X    outspeed = _tty.sg_ospeed;        /* for tputs() */
  2128. X    ERASECH = _tty.sg_erase;        /* for finish_command() */
  2129. X    KILLCH = _tty.sg_kill;        /* for finish_command() */
  2130. X    if (GT = ((_tty.sg_flags & XTABS) != XTABS))
  2131. X    /* we have tabs, so that's OK */;
  2132. X    else
  2133. X    _tty.sg_flags &= ~XTABS;
  2134. X# endif /* TERMIOS */
  2135. X#endif /* TERMIO */
  2136. X
  2137. X    /* The following could be a table but I can't be sure that there isn't */
  2138. X    /* some degree of sparsity out there in the world. */
  2139. X
  2140. X    switch (outspeed) {            /* 1 second of padding */
  2141. X#ifdef BEXTA
  2142. X        case BEXTA:  just_a_sec = 1920; break;
  2143. X#else
  2144. X#ifdef B19200
  2145. X        case B19200: just_a_sec = 1920; break;
  2146. X#endif
  2147. X#endif
  2148. X        case B9600:  just_a_sec =  960; break;
  2149. X        case B4800:  just_a_sec =  480; break;
  2150. X        case B2400:  just_a_sec =  240; break;
  2151. X        case B1800:  just_a_sec =  180; break;
  2152. X        case B1200:  just_a_sec =  120; break;
  2153. X        case B600:   just_a_sec =   60; break;
  2154. X    case B300:   just_a_sec =   30; break;
  2155. X    /* do I really have to type the rest of this??? */
  2156. X        case B200:   just_a_sec =   20; break;
  2157. X        case B150:   just_a_sec =   15; break;
  2158. X        case B134:   just_a_sec =   13; break;
  2159. X        case B110:   just_a_sec =   11; break;
  2160. X        case B75:    just_a_sec =    8; break;
  2161. X        case B50:    just_a_sec =    5; break;
  2162. X        default:     just_a_sec =  960; break;
  2163. X                    /* if we are running detached I */
  2164. X    }                    /*  don't want to know about it! */
  2165. X}
  2166. X
  2167. X/* set terminal characteristics */
  2168. X
  2169. void
  2170. term_set(tcbuf)
  2171. char *tcbuf;        /* temp area for "uncompiled" termcap entry */
  2172. X{
  2173. X    char *tmpaddr;            /* must not be register */
  2174. X    register char *tmpstr;
  2175. X    char *tgetstr();
  2176. X    char *s;
  2177. X    int status;
  2178. X#ifdef TIOCGWINSZ
  2179. X    struct winsize winsize;
  2180. X#endif
  2181. X
  2182. X#ifdef PENDING
  2183. X#if ! defined (FIONREAD) && ! defined (RDCHK)
  2184. X    /* do no delay reads on something that always gets closed on exit */
  2185. X
  2186. X    devtty = open("/dev/tty",0);
  2187. X    if (devtty < 0) {
  2188. X    printf(cantopen,"/dev/tty") FLUSH;
  2189. X    finalize(1);
  2190. X    }
  2191. X    fcntl(devtty,F_SETFL,O_NDELAY);
  2192. X#endif
  2193. X#endif
  2194. X    
  2195. X    /* get all that good termcap stuff */
  2196. X
  2197. X#ifdef HAVETERMLIB
  2198. X    status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  2199. X    if (status < 1) {
  2200. X#ifdef VERBOSE
  2201. X    printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  2202. X#else
  2203. X    fputs("Termcap botch\n",stdout) FLUSH;
  2204. X#endif
  2205. X    finalize(1);
  2206. X    }
  2207. X    tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  2208. X    s = Tgetstr("pc");            /* get pad character */
  2209. X    PC = *s;                /* get it where tputs wants it */
  2210. X    if (!tgetflag("bs")) {        /* is backspace not used? */
  2211. X    BC = Tgetstr("bc");        /* find out what is */
  2212. X    if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  2213. X        BC = Tgetstr("le");
  2214. X    } else
  2215. X    BC = "\b";            /* make a backspace handy */
  2216. X    UP = Tgetstr("up");            /* move up a line */
  2217. X    if (!*UP)                /* no UP string? */
  2218. X    marking = 0;            /* disable any marking */
  2219. X    if (muck_up_clear)            /* this is for weird HPs */
  2220. X    CL = "\n\n\n\n";
  2221. X    else
  2222. X    CL = Tgetstr("cl");        /* get clear string */
  2223. X    CE = Tgetstr("ce");            /* clear to end of line string */
  2224. X    TI = Tgetstr("ti");            /* initialize display */
  2225. X    TE = Tgetstr("te");            /* reset display */
  2226. X#if defined(CLEAREOL) || defined(USETHREADS)
  2227. X    HO = Tgetstr("ho");            /* home cursor if no CM */
  2228. X    CM = Tgetstr("cm");            /* cursor motion */
  2229. X    if (*CM || *HO)
  2230. X    can_home = TRUE;
  2231. X#endif
  2232. X#ifdef CLEAREOL
  2233. X    CD = Tgetstr("cd");            /* clear to end of display */
  2234. X    if (!*CE || !*CD || !can_home)    /* can we CE, CD, and home? */
  2235. X    can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  2236. X    if (!*CE) CE = CD;
  2237. X#endif /* CLEAREOL */
  2238. X#ifdef USETHREADS
  2239. X    upcost = strlen(UP);
  2240. X#endif
  2241. X    SO = Tgetstr("so");            /* begin standout */
  2242. X    SE = Tgetstr("se");            /* end standout */
  2243. X    if ((SG = tgetnum("sg"))<0)
  2244. X    SG = 0;                /* blanks left by SG, SE */
  2245. X    US = Tgetstr("us");            /* start underline */
  2246. X    UE = Tgetstr("ue");            /* end underline */
  2247. X    if ((UG = tgetnum("ug"))<0)
  2248. X    UG = 0;                /* blanks left by US, UE */
  2249. X    if (*US)
  2250. X    UC = nullstr;            /* UC must not be NULL */
  2251. X    else
  2252. X    UC = Tgetstr("uc");        /* underline a character */
  2253. X    if (!*US && !*UC) {            /* no underline mode? */
  2254. X    US = SO;            /* substitute standout mode */
  2255. X    UE = SE;
  2256. X    UG = SG;
  2257. X    }
  2258. X    LINES = tgetnum("li");        /* lines per page */
  2259. X    COLS = tgetnum("co");        /* columns on page */
  2260. X
  2261. X#ifdef TIOCGWINSZ
  2262. X    { struct winsize ws;
  2263. X    if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  2264. X        LINES = ws.ws_row;
  2265. X        COLS = ws.ws_col;
  2266. X    }
  2267. X    }
  2268. X#endif
  2269. X    
  2270. X    AM = tgetflag("am");        /* terminal wraps automatically? */
  2271. X    XN = tgetflag("xn");        /* then eats next newline? */
  2272. X    VB = Tgetstr("vb");
  2273. X    if (!*VB)
  2274. X    VB = "\007";
  2275. X    CR = Tgetstr("cr");
  2276. X    if (!*CR) {
  2277. X    if (tgetflag("nc") && *UP) {
  2278. X        CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  2279. X        sprintf(CR,"%s\r",UP);
  2280. X    }
  2281. X    else
  2282. X        CR = "\r";
  2283. X    }
  2284. X#ifdef TIOCGWINSZ
  2285. X    if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
  2286. X        if (winsize.ws_row>0) LINES=winsize.ws_row;
  2287. X        if (winsize.ws_col>0) COLS=winsize.ws_col;
  2288. X    }
  2289. X#endif
  2290. X#else
  2291. X    ??????                /* Roll your own... */
  2292. X#endif
  2293. X    termlib_init();
  2294. X    line_col_calcs();
  2295. X    noecho();                /* turn off echo */
  2296. X    crmode();                /* enter cbreak mode */
  2297. X
  2298. X#ifdef PUSHBACK
  2299. X    mac_init(tcbuf);
  2300. X#endif
  2301. X}
  2302. X
  2303. X#ifdef PUSHBACK
  2304. void
  2305. mac_init(tcbuf)
  2306. char *tcbuf;
  2307. X{
  2308. X    char tmpbuf[1024];
  2309. X
  2310. X    tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
  2311. X    if (tmpfp != Nullfp) {
  2312. X    while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  2313. X        mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  2314. X    }
  2315. X    fclose(tmpfp);
  2316. X    }
  2317. X}
  2318. X
  2319. void
  2320. mac_line(line,tmpbuf,tbsize)
  2321. char *line;
  2322. char *tmpbuf;
  2323. int tbsize;
  2324. X{
  2325. X    register char *s, *m;
  2326. X    register KEYMAP *curmap;
  2327. X    register int ch;
  2328. X    register int garbage = 0;
  2329. X    static char override[] = "\nkeymap overrides string\n";
  2330. X
  2331. X    if (topmap == Null(KEYMAP*))
  2332. X    topmap = newkeymap();
  2333. X    if (*line == '#' || *line == '\n')
  2334. X    return;
  2335. X    if (line[ch = strlen(line)-1] == '\n')
  2336. X    line[ch] = '\0';
  2337. X    m = dointerp(tmpbuf,tbsize,line," \t");
  2338. X    if (!*m)
  2339. X    return;
  2340. X    while (*m == ' ' || *m == '\t') m++;
  2341. X    for (s=tmpbuf,curmap=topmap; *s; s++) {
  2342. X    ch = *s & 0177;
  2343. X    if (s[1] == '+' && isdigit(s[2])) {
  2344. X        s += 2;
  2345. X        garbage = (*s & KM_GMASK) << KM_GSHIFT;
  2346. X    }
  2347. X    else
  2348. X        garbage = 0;
  2349. X    if (s[1]) {
  2350. X        if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  2351. X        fputs(override,stdout) FLUSH;
  2352. X        free(curmap->km_ptr[ch].km_str);
  2353. X        curmap->km_ptr[ch].km_str = Nullch;
  2354. X        }
  2355. X        curmap->km_type[ch] = KM_KEYMAP + garbage;
  2356. X        if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  2357. X        curmap->km_ptr[ch].km_km = newkeymap();
  2358. X        curmap = curmap->km_ptr[ch].km_km;
  2359. X    }
  2360. X    else {
  2361. X        if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  2362. X        fputs(override,stdout) FLUSH;
  2363. X        else {
  2364. X        curmap->km_type[ch] = KM_STRING + garbage;
  2365. X        curmap->km_ptr[ch].km_str = savestr(m);
  2366. X        }
  2367. X    }
  2368. X    }
  2369. X}
  2370. X
  2371. KEYMAP*
  2372. newkeymap()
  2373. X{
  2374. X    register int i;
  2375. X    register KEYMAP *map;
  2376. X
  2377. X#ifndef lint
  2378. X    map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  2379. X#else
  2380. X    map = Null(KEYMAP*);
  2381. X#endif /* lint */
  2382. X    for (i=127; i>=0; --i) {
  2383. X    map->km_ptr[i].km_km = Null(KEYMAP*);
  2384. X    map->km_type[i] = KM_NOTHIN;
  2385. X    }
  2386. X    return map;
  2387. X}
  2388. X
  2389. void
  2390. show_macros()
  2391. X{
  2392. X    char prebuf[64];
  2393. X
  2394. X    if (topmap != Null(KEYMAP*)) {
  2395. X    print_lines("Macros:\n",STANDOUT);
  2396. X    *prebuf = '\0';
  2397. X    show_keymap(topmap,prebuf);
  2398. X    }
  2399. X    else {
  2400. X    print_lines("No macros defined.\n", NOMARKING);
  2401. X    }
  2402. X}
  2403. X
  2404. void
  2405. show_keymap(curmap,prefix)
  2406. register KEYMAP *curmap;
  2407. char *prefix;
  2408. X{
  2409. X    register int i;
  2410. X    register char *next = prefix + strlen(prefix);
  2411. X    register int kt;
  2412. X
  2413. X    for (i=0; i<128; i++) {
  2414. X    if (kt = curmap->km_type[i]) {
  2415. X        if (i < ' ')
  2416. X        sprintf(next,"^%c",i+64);
  2417. X        else if (i == ' ')
  2418. X        strcpy(next,"\\040");
  2419. X        else if (i == 127)
  2420. X        strcpy(next,"^?");
  2421. X        else
  2422. X        sprintf(next,"%c",i);
  2423. X        if ((kt >> KM_GSHIFT) & KM_GMASK) {
  2424. X        sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  2425. X        strcat(next,cmd_buf);
  2426. X        }
  2427. X        switch (kt & KM_TMASK) {
  2428. X        case KM_NOTHIN:
  2429. X        sprintf(cmd_buf,"%s    %c\n",prefix,i);
  2430. X        print_lines(cmd_buf,NOMARKING);
  2431. X        break;
  2432. X        case KM_KEYMAP:
  2433. X        show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  2434. X        break;
  2435. X        case KM_STRING:
  2436. X        sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  2437. X        print_lines(cmd_buf,NOMARKING);
  2438. X        break;
  2439. X        case KM_BOGUS:
  2440. X        sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  2441. X        print_lines(cmd_buf,STANDOUT);
  2442. X        break;
  2443. X        }
  2444. X    }
  2445. X    }
  2446. X}
  2447. X
  2448. X#endif
  2449. X
  2450. X/* routine to pass to tputs */
  2451. X
  2452. char
  2453. putchr(ch)
  2454. register char_int ch;
  2455. X{
  2456. X    putchar(ch);
  2457. X#ifdef lint
  2458. X    ch = Null(char);
  2459. X    ch = ch;
  2460. X#endif
  2461. X    return((char) 0);
  2462. X}
  2463. X
  2464. X/* input the 2nd and succeeding characters of a multi-character command */
  2465. X/* returns TRUE if command finished, FALSE if they rubbed out first character */
  2466. X
  2467. bool
  2468. finish_command(donewline)
  2469. int donewline;
  2470. X{
  2471. X    register char *s;
  2472. X    register bool quoteone = FALSE;
  2473. X
  2474. X    s = buf;
  2475. X    if (s[1] != FINISHCMD)        /* someone faking up a command? */
  2476. X    return TRUE;
  2477. X    do {
  2478. X      top:
  2479. X    if (*(unsigned char *)s < ' ') {
  2480. X        putchar('^');
  2481. X        putchar(*s | 64);
  2482. X    }
  2483. X    else if (*s == '\177') {
  2484. X        putchar('^');
  2485. X        putchar('?');
  2486. X    }
  2487. X    else
  2488. X        putchar(*s);        /* echo previous character */
  2489. X    s++;
  2490. re_read:
  2491. X    fflush(stdout);
  2492. X    getcmd(s);
  2493. X    if (quoteone) {
  2494. X        quoteone = FALSE;
  2495. X        continue;
  2496. X    }
  2497. X    if (errno || *s == '\f') {
  2498. X        *s = Ctl('r');        /* force rewrite on CONT */
  2499. X    }
  2500. X    if (*s == '\033') {        /* substitution desired? */
  2501. X#ifdef ESCSUBS
  2502. X        char tmpbuf[4], *cpybuf;
  2503. X
  2504. X        tmpbuf[0] = '%';
  2505. X        read_tty(&tmpbuf[1],1);
  2506. X#ifdef RAWONLY
  2507. X        tmpbuf[1] &= 0177;
  2508. X#endif
  2509. X        tmpbuf[2] = '\0';
  2510. X        if (tmpbuf[1] == 'h') {
  2511. X        (void) help_subs();
  2512. X        *s = '\0';
  2513. X        reprint();
  2514. X        goto re_read;
  2515. X        }
  2516. X        else if (tmpbuf[1] == '\033') {
  2517. X        *s = '\0';
  2518. X        cpybuf = savestr(buf);
  2519. X        interp(buf, (sizeof buf), cpybuf);
  2520. X        free(cpybuf);
  2521. X        s = buf + strlen(buf);
  2522. X        reprint();
  2523. X        goto re_read;
  2524. X        }
  2525. X        else {
  2526. X        interp(s,(sizeof buf) - (s-buf),tmpbuf);
  2527. X        fputs(s,stdout);
  2528. X        s += strlen(s);
  2529. X        }
  2530. X        goto re_read;
  2531. X#else
  2532. X        notincl("^[");
  2533. X        *s = '\0';
  2534. X        reprint();
  2535. X        goto re_read;
  2536. X#endif
  2537. X    }
  2538. X    else if (*s == ERASECH) {    /* they want to rubout a char? */
  2539. X        rubout();
  2540. X        s--;            /* discount the char rubbed out */
  2541. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2542. X        rubout();
  2543. X        if (s == buf) {        /* entire string gone? */
  2544. X        fflush(stdout);        /* return to single char command mode */
  2545. X        return FALSE;
  2546. X        }
  2547. X        else
  2548. X        goto re_read;
  2549. X    }
  2550. X    else if (*s == KILLCH) {    /* wipe out the whole line? */
  2551. X        while (s-- != buf) {    /* emulate that many ERASEs */
  2552. X        rubout();
  2553. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2554. X            rubout();
  2555. X        }
  2556. X        fflush(stdout);
  2557. X        return FALSE;        /* return to single char mode */
  2558. X    }
  2559. X#ifdef WORDERASE
  2560. X    else if (*s == Ctl('w')) {    /* wipe out one word? */
  2561. X        *s-- = ' ';
  2562. X        while (!isspace(*s) || isspace(s[1])) {
  2563. X        rubout();
  2564. X        if (s-- == buf) {
  2565. X            fflush(stdout);
  2566. X            return FALSE;    /* return to single char mode */
  2567. X        }
  2568. X        if (*(unsigned char *)s < ' ' || *s == '\177')
  2569. X            rubout();
  2570. X        }
  2571. X        s++;
  2572. X        goto re_read;
  2573. X    }
  2574. X#endif
  2575. X    else if (*s == Ctl('r')) {
  2576. X        *s = '\0';
  2577. X        reprint();
  2578. X        goto re_read;
  2579. X    }
  2580. X    else if (*s == Ctl('v')) {
  2581. X        putchar('^');
  2582. X        backspace();
  2583. X        fflush(stdout);
  2584. X        getcmd(s);
  2585. X        goto top;
  2586. X    }
  2587. X    else if (*s == '\\') {
  2588. X        quoteone = TRUE;
  2589. X    }
  2590. X#ifdef cray
  2591. X    } while (*s != '\r');        /* till a newline (not echoed) */
  2592. X#else
  2593. X    } while (*s != '\n');        /* till a newline (not echoed) */
  2594. X#endif
  2595. X    *s = '\0';                /* terminate the string nicely */
  2596. X    if (donewline)
  2597. X    putchar('\n') FLUSH;
  2598. X    return TRUE;            /* say we succeeded */
  2599. X}
  2600. X
  2601. X/* discard any characters typed ahead */
  2602. X
  2603. void
  2604. eat_typeahead()
  2605. X{
  2606. X#ifdef PUSHBACK
  2607. X    if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  2608. X#else
  2609. X    if (!typeahead)
  2610. X#endif
  2611. X    {
  2612. X#ifdef PENDING
  2613. X    while (input_pending())
  2614. X        read_tty(buf,sizeof(buf));
  2615. X#else /* this is probably v7 */
  2616. X#if defined(TERMIO) || defined(TERMIOS)
  2617. X    ioctl(_tty_ch,TCSETAW,&_tty);
  2618. X#else
  2619. X    ioctl(_tty_ch,TIOCSETP,&_tty);
  2620. X#endif
  2621. X#endif
  2622. X    }
  2623. X}
  2624. X
  2625. void
  2626. settle_down()
  2627. X{
  2628. X    dingaling();
  2629. X    fflush(stdout);
  2630. X/*    sleep(1); */
  2631. X#ifdef PUSHBACK
  2632. X    nextout = nextin;            /* empty circlebuf */
  2633. X#endif
  2634. X    eat_typeahead();
  2635. X}
  2636. X
  2637. X#ifdef PUSHBACK
  2638. X/* read a character from the terminal, with multi-character pushback */
  2639. X
  2640. int
  2641. read_tty(addr,size)
  2642. char *addr;
  2643. int size;
  2644. X{
  2645. X    if (nextout != nextin) {
  2646. X    *addr = circlebuf[nextout++];
  2647. X    nextout %= PUSHSIZE;
  2648. X    return 1;
  2649. X    }
  2650. X    else {
  2651. X    size = read(0,addr,size);
  2652. X#ifdef RAWONLY
  2653. X    *addr &= 0177;
  2654. X#endif
  2655. X    return size;
  2656. X    }
  2657. X}
  2658. X
  2659. X#ifdef PENDING
  2660. X#if ! defined (FIONREAD) && ! defined (RDCHK)
  2661. int
  2662. circfill()
  2663. X{
  2664. X    register int Howmany;
  2665. X
  2666. X    errno = 0;
  2667. X    Howmany = read(devtty,circlebuf+nextin,1);
  2668. X
  2669. X    if (Howmany < 0 && (errno == EAGAIN || errno == EINTR))
  2670. X    Howmany = 0;
  2671. X    if (Howmany) {
  2672. X    nextin += Howmany;
  2673. X    nextin %= PUSHSIZE;
  2674. X    }
  2675. X    return Howmany;
  2676. X}
  2677. X#endif /* PENDING */
  2678. X#endif /* FIONREAD */
  2679. X
  2680. void
  2681. pushchar(c)
  2682. char_int c;
  2683. X{
  2684. X    nextout--;
  2685. X    if (nextout < 0)
  2686. X    nextout = PUSHSIZE - 1;
  2687. X    if (nextout == nextin) {
  2688. X    fputs("\npushback buffer overflow\n",stdout) FLUSH;
  2689. X    sig_catcher(0);
  2690. X    }
  2691. X    circlebuf[nextout] = c;
  2692. X}
  2693. X
  2694. X#else /* PUSHBACK */
  2695. X#ifndef read_tty
  2696. X/* read a character from the terminal, with hacks for O_NDELAY reads */
  2697. X
  2698. int
  2699. read_tty(addr,size)
  2700. char *addr;
  2701. int size;
  2702. X{
  2703. X    if (is_input) {
  2704. X    *addr = pending_ch;
  2705. X    is_input = FALSE;
  2706. X    return 1;
  2707. X    }
  2708. X    else {
  2709. X    size = read(0,addr,size);
  2710. X#ifdef RAWONLY
  2711. X    *addr &= 0177;
  2712. X#endif
  2713. X    return size;
  2714. X    }
  2715. X}
  2716. X#endif /* read_tty */
  2717. X#endif /* PUSHBACK */
  2718. X
  2719. X/* print an underlined string, one way or another */
  2720. X
  2721. void
  2722. underprint(s)
  2723. register char *s;
  2724. X{
  2725. X    assert(UC);
  2726. X    if (*UC) {        /* char by char underline? */
  2727. X    while (*s) {
  2728. X        if (*(unsigned char *)s < ' ') {
  2729. X        putchar('^');
  2730. X        backspace();/* back up over it */
  2731. X        underchar();/* and do the underline */
  2732. X        putchar(*s+64);
  2733. X        backspace();/* back up over it */
  2734. X        underchar();/* and do the underline */
  2735. X        }
  2736. X        else {
  2737. X        putchar(*s);
  2738. X        backspace();/* back up over it */
  2739. X        underchar();/* and do the underline */
  2740. X        }
  2741. X        s++;
  2742. X    }
  2743. X    }
  2744. X    else {        /* start and stop underline */
  2745. X    underline();    /* start underlining */
  2746. X    while (*s) {
  2747. X        if (*(unsigned char *)s < ' ') {
  2748. X        putchar('^');
  2749. X        putchar(*s+64);
  2750. X        }
  2751. X        else
  2752. X        putchar(*s);
  2753. X        s++;
  2754. X    }
  2755. X    un_underline();    /* stop underlining */
  2756. X    }
  2757. X}
  2758. X
  2759. X/* keep screen from flashing strangely on magic cookie terminals */
  2760. X
  2761. X#ifdef NOFIREWORKS
  2762. void
  2763. no_sofire()
  2764. X{
  2765. X    if (*UP && *SE) {        /* should we disable fireworks? */
  2766. X    putchar('\n');
  2767. X    un_standout();
  2768. X    up_line();
  2769. X    carriage_return();
  2770. X    }
  2771. X}
  2772. X
  2773. void
  2774. no_ulfire()
  2775. X{
  2776. X    if (*UP && *US) {        /* should we disable fireworks? */
  2777. X    putchar('\n');
  2778. X    un_underline();
  2779. X    up_line();
  2780. X    carriage_return();
  2781. X    }
  2782. X}
  2783. X#endif
  2784. X
  2785. X/* get a character into a buffer */
  2786. X
  2787. void
  2788. getcmd(whatbuf)
  2789. register char *whatbuf;
  2790. X{
  2791. X#ifdef PUSHBACK
  2792. X    register KEYMAP *curmap;
  2793. X    register int i;
  2794. X    bool no_macros; 
  2795. X    int times = 0;            /* loop detector */
  2796. X    char scrchar;
  2797. X
  2798. tryagain:
  2799. X    curmap = topmap;
  2800. X    no_macros = (whatbuf != buf && nextin == nextout); 
  2801. X#endif
  2802. X    for (;;) {
  2803. X    int_count = 0;
  2804. X    errno = 0;
  2805. X    if (read_tty(whatbuf,1) < 0){
  2806. X        if (!errno)
  2807. X            errno = EINTR;
  2808. X        if (errno == EINTR)
  2809. X        return;
  2810. X        perror(readerr);
  2811. X        sig_catcher(0);
  2812. X    }
  2813. X#ifdef PUSHBACK
  2814. X    if (*whatbuf & 0200 || no_macros) {
  2815. X        *whatbuf &= 0177;
  2816. X        goto got_canonical;
  2817. X    }
  2818. X    if (curmap == Null(KEYMAP*))
  2819. X        goto got_canonical;
  2820. X    for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  2821. X        read_tty(&scrchar,1);
  2822. X    }
  2823. X    switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  2824. X    case KM_NOTHIN:            /* no entry? */
  2825. X        if (curmap == topmap)    /* unmapped canonical */
  2826. X        goto got_canonical;
  2827. X        settle_down();
  2828. X        goto tryagain;
  2829. X    case KM_KEYMAP:            /* another keymap? */
  2830. X        curmap = curmap->km_ptr[*whatbuf].km_km;
  2831. X        assert(curmap != Null(KEYMAP*));
  2832. X        break;
  2833. X    case KM_STRING:            /* a string? */
  2834. X        pushstring(curmap->km_ptr[*whatbuf].km_str);
  2835. X        if (++times > 20) {        /* loop? */
  2836. X        fputs("\nmacro loop?\n",stdout);
  2837. X        settle_down();
  2838. X        }
  2839. X        no_macros = FALSE;
  2840. X        goto tryagain;
  2841. X    }
  2842. X#else
  2843. X#ifdef RAWONLY
  2844. X    *whatbuf &= 0177;
  2845. X#endif
  2846. X    break;
  2847. X#endif
  2848. X    }
  2849. X
  2850. got_canonical:
  2851. X#if !defined(TERMIO) && !defined(TERMIOS)
  2852. X    if (*whatbuf == '\r')
  2853. X    *whatbuf = '\n';
  2854. X#endif
  2855. X    if (whatbuf == buf)
  2856. X    whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  2857. X}
  2858. X
  2859. X#ifdef PUSHBACK
  2860. void
  2861. pushstring(str)
  2862. char *str;
  2863. X{
  2864. X    register int i;
  2865. X    char tmpbuf[PUSHSIZE];
  2866. X    register char *s = tmpbuf;
  2867. X
  2868. X    assert(str != Nullch);
  2869. X    interp(s,PUSHSIZE,str);
  2870. X    for (i = strlen(s)-1; i >= 0; --i) {
  2871. X    s[i] ^= 0200; 
  2872. X    pushchar(s[i]);
  2873. X    }
  2874. X}
  2875. X#endif
  2876. X
  2877. int
  2878. get_anything()
  2879. X{
  2880. X    char tmpbuf[2];
  2881. X
  2882. reask_anything:
  2883. X    unflush_output();            /* disable any ^O in effect */
  2884. X    standout();
  2885. X#ifdef VERBOSE
  2886. X    IF(verbose)
  2887. X    fputs("[Type space to continue] ",stdout);
  2888. X    ELSE
  2889. X#endif
  2890. X#ifdef TERSE
  2891. X    fputs("[MORE] ",stdout);
  2892. X#endif
  2893. X    un_standout();
  2894. X    fflush(stdout);
  2895. X    eat_typeahead();
  2896. X    if (int_count) {
  2897. X    return -1;
  2898. X    }
  2899. X    collect_subjects();            /* loads subject cache until */
  2900. X                    /* input is pending */
  2901. X    getcmd(tmpbuf);
  2902. X    if (errno || *tmpbuf == '\f') {
  2903. X    putchar('\n') FLUSH;        /* if return from stop signal */
  2904. X    goto reask_anything;        /* give them a prompt again */
  2905. X    }
  2906. X    if (*tmpbuf == 'h') {
  2907. X#ifdef VERBOSE
  2908. X    IF(verbose)
  2909. X        fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
  2910. X    ELSE
  2911. X#endif
  2912. X#ifdef TERSE
  2913. X        fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
  2914. X#endif
  2915. X    goto reask_anything;
  2916. X    }
  2917. X    else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  2918. X    carriage_return();
  2919. X    erase_eol();    /* erase the prompt */
  2920. X    carriage_return();
  2921. X    return *tmpbuf == 'q' ? -1 : *tmpbuf;
  2922. X    }
  2923. X    if (*tmpbuf == '\n') {
  2924. X    page_line = LINES - 1;
  2925. X    carriage_return();
  2926. X    erase_eol();
  2927. X    carriage_return();
  2928. X    }
  2929. X    else {
  2930. X    page_line = 1;
  2931. X    if (erase_screen)        /* -e? */
  2932. X        clear();            /* clear screen */
  2933. X    else {
  2934. X        carriage_return();
  2935. X        erase_eol();        /* erase the prompt */
  2936. X        carriage_return();
  2937. X    }
  2938. X    }
  2939. X    return 0;
  2940. X}
  2941. X
  2942. X#ifdef USETHREADS
  2943. int
  2944. pause_getcmd()
  2945. X{
  2946. X    unflush_output();            /* disable any ^O in effect */
  2947. X    standout();
  2948. X#ifdef VERBOSE
  2949. X    IF(verbose)
  2950. X    fputs("[Type space or a command] ",stdout);
  2951. X    ELSE
  2952. X#endif
  2953. X#ifdef TERSE
  2954. X    fputs("[CMD] ",stdout);
  2955. X#endif
  2956. X    un_standout();
  2957. X    fflush(stdout);
  2958. X    eat_typeahead();
  2959. X    if (int_count) {
  2960. X    return -1;
  2961. X    }
  2962. X    getcmd(buf);
  2963. X    if (errno || *buf == '\f') {
  2964. X    return 0;            /* if return from stop signal */
  2965. X    }
  2966. X    else if (*buf != ' ') {
  2967. X    carriage_return();
  2968. X    erase_eol();    /* erase the prompt */
  2969. X    carriage_return();
  2970. X    return *buf;
  2971. X    }
  2972. X    return 0;
  2973. X}
  2974. X#endif
  2975. X
  2976. void
  2977. in_char(prompt, newmode)
  2978. char *prompt;
  2979. char_int newmode;
  2980. X{
  2981. X    char oldmode = mode;
  2982. X
  2983. reask_in_char:
  2984. X    unflush_output();            /* disable any ^O in effect */
  2985. X    fputs(prompt,stdout);
  2986. X    fflush(stdout);
  2987. X    eat_typeahead();
  2988. X    mode = newmode;
  2989. X    getcmd(buf);
  2990. X    if (errno || *buf == '\f') {
  2991. X    putchar('\n') FLUSH;        /* if return from stop signal */
  2992. X    goto reask_in_char;        /* give them a prompt again */
  2993. X    }
  2994. X    mode = oldmode;
  2995. X}
  2996. X
  2997. int
  2998. print_lines(what_to_print,hilite)
  2999. char *what_to_print;
  3000. int hilite;
  3001. X{
  3002. X    register char *s;
  3003. X    register int i;
  3004. X
  3005. X    if (page_line < 0)            /* they do not want to see this? */
  3006. X    return -1;
  3007. X    for (s=what_to_print; *s; ) {
  3008. X    if (page_line >= LINES || int_count) {
  3009. X        if (i = -1, int_count || (i = get_anything())) {
  3010. X        page_line = -1;        /* disable further print_lines */
  3011. X        return i;
  3012. X        }
  3013. X    }
  3014. X    page_line++;
  3015. X    if (hilite == STANDOUT) {
  3016. X#ifdef NOFIREWORKS
  3017. X        if (erase_screen)
  3018. X        no_sofire();
  3019. X#endif
  3020. X        standout();
  3021. X    }
  3022. X    else if (hilite == UNDERLINE) {
  3023. X#ifdef NOFIREWORKS
  3024. X        if (erase_screen)
  3025. X        no_ulfire();
  3026. X#endif
  3027. X        underline();
  3028. X    }
  3029. X    for (i=0; i<COLS; i++) {
  3030. X        if (!*s)
  3031. X        break;
  3032. X        if (*(unsigned char *)s >= ' ')
  3033. X        putchar(*s);
  3034. X        else if (*s == '\t') {
  3035. X        putchar(*s);
  3036. X        i = ((i+8) & ~7) - 1; 
  3037. X        }
  3038. X        else if (*s == '\n') {
  3039. X        i = 32000;
  3040. X        }
  3041. X        else {
  3042. X        i++;
  3043. X        putchar('^');
  3044. X        putchar(*s + 64);
  3045. X        }
  3046. X        s++;
  3047. X    }
  3048. X    if (i) {
  3049. X        if (hilite == STANDOUT)
  3050. X        un_standout();
  3051. X        else if (hilite == UNDERLINE)
  3052. X        un_underline();
  3053. X        if (AM && i == COLS)
  3054. X        fflush(stdout);
  3055. X        else
  3056. X        putchar('\n') FLUSH;
  3057. X    }
  3058. X    }
  3059. X    return 0;
  3060. X}
  3061. X
  3062. void
  3063. page_init()
  3064. X{
  3065. X    page_line = 1;
  3066. X    if (erase_screen)
  3067. X    clear();
  3068. X    else
  3069. X    putchar('\n') FLUSH;
  3070. X}
  3071. X
  3072. void
  3073. pad(num)
  3074. int num;
  3075. X{
  3076. X    register int i;
  3077. X
  3078. X    for (i = num; i; --i)
  3079. X    putchar(PC);
  3080. X    fflush(stdout);
  3081. X}
  3082. X
  3083. X/* echo the command just typed */
  3084. X
  3085. X#ifdef VERIFY
  3086. void
  3087. printcmd()
  3088. X{
  3089. X    if (verify && buf[1] == FINISHCMD) {
  3090. X    if (*(unsigned char *)buf < ' ') {
  3091. X        putchar('^');
  3092. X        putchar(*buf | 64);
  3093. X        backspace();
  3094. X        backspace();
  3095. X    }
  3096. X    else {
  3097. X        putchar(*buf);
  3098. X        backspace();
  3099. X    }
  3100. X    fflush(stdout);
  3101. X    }
  3102. X}
  3103. X#endif
  3104. X
  3105. void
  3106. rubout()
  3107. X{
  3108. X    backspace();            /* do the old backspace, */
  3109. X    putchar(' ');            /*   space, */
  3110. X    backspace();            /*     backspace trick */
  3111. X}
  3112. X
  3113. void
  3114. reprint()
  3115. X{
  3116. X    register char *s;
  3117. X
  3118. X    fputs("^R\n",stdout) FLUSH;
  3119. X    for (s = buf; *s; s++) {
  3120. X    if (*(unsigned char *)s < ' ') {
  3121. X        putchar('^');
  3122. X        putchar(*s | 64);
  3123. X    }
  3124. X    else
  3125. X        putchar(*s);
  3126. X    }
  3127. X}
  3128. X
  3129. X#if defined(CLEAREOL) || defined(USETHREADS)
  3130. void
  3131. home_cursor()
  3132. X{
  3133. X    char *tgoto();
  3134. X
  3135. X    if (!*HO) {            /* no home sequence? */
  3136. X    if (!*CM) {        /* no cursor motion either? */
  3137. X        fputs ("\n\n\n", stdout);
  3138. X        return;        /* forget it. */
  3139. X    }
  3140. X    tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  3141. X    return;
  3142. X    }
  3143. X    else {            /* we have home sequence */
  3144. X    tputs (HO, 1, putchr);    /* home via HO */
  3145. X    }
  3146. X}
  3147. X#endif
  3148. X
  3149. X#ifdef USETHREADS
  3150. void
  3151. goto_line(from,to)    /* assumes caller is already at beginning of line */
  3152. int from,to;
  3153. X{
  3154. X    char *tgoto(), *str;
  3155. X    int cmcost;
  3156. X
  3157. X    if (from == to) {
  3158. X    return;
  3159. X    }
  3160. X    if (*CM && !muck_up_clear) {
  3161. X    cmcost = strlen(str = tgoto(CM,0,to));
  3162. X    } else {
  3163. X    cmcost = 9999;
  3164. X    }
  3165. X    if (to > from) {
  3166. X      go_down:
  3167. X    if (to - from <= cmcost) {
  3168. X        while(from++ < to) {
  3169. X        putchar('\n');
  3170. X        }
  3171. X        return;
  3172. X    }
  3173. X    } else if(*UP) {
  3174. X    if ((from - to) * upcost <= cmcost) {
  3175. X        while(from-- > to) {
  3176. X        tputs(UP,1,putchr);
  3177. X        }
  3178. X        return;
  3179. X    }
  3180. X    } else if (cmcost == 9999) {
  3181. X    home_cursor();
  3182. X    from = 0;
  3183. X    goto go_down;
  3184. X    }
  3185. X    tputs(str,1,putchr);
  3186. X}
  3187. X#endif
  3188. X
  3189. void
  3190. line_col_calcs()
  3191. X{
  3192. X     if (LINES > 0) {            /* is this a crt? */
  3193. X      if ((!initlines) || (!initlines_specified))
  3194. X           /* no -i or unreasonable value for initlines */
  3195. X           if (outspeed >= B9600)     /* whole page at >= 9600 baud */
  3196. X            initlines = LINES;
  3197. X           else if (outspeed >= B4800)/* 16 lines at 4800 */
  3198. X            initlines = 16;
  3199. X           else            /* otherwise just header */
  3200. X            initlines = 8;
  3201. X     }
  3202. X     else {                /* not a crt */
  3203. X      LINES = 30000;        /* so don't page */
  3204. X      CL = "\n\n";            /* put a couple of lines between */
  3205. X      if ((!initlines) || (!initlines_specified))
  3206. X           /* make initlines reasonable */
  3207. X           initlines = 8;
  3208. X     }
  3209. X     if (COLS <= 0)
  3210. X      COLS = 80;
  3211. X}
  3212. X
  3213. X
  3214. X#ifdef SIGWINCH
  3215. SIGRET
  3216. winch_catcher()
  3217. X{
  3218. X     /* Reset signal in case of System V dain bramage */
  3219. X     sigset(SIGWINCH, winch_catcher);
  3220. X
  3221. X     /* Come here if window size change signal received */
  3222. X#ifdef TIOCGWINSZ
  3223. X     { struct winsize ws;
  3224. X       if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  3225. X     LINES = ws.ws_row;
  3226. X     COLS = ws.ws_col;
  3227. X     line_col_calcs();
  3228. X       }
  3229. X     }
  3230. X#else
  3231. X     /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  3232. X     /* almost certainly something wrong.  Figure it out for yourself, */
  3233. X     /* because I don't know now to deal :-)                           */
  3234. X#endif
  3235. X}
  3236. X#endif
  3237. void
  3238. termlib_init()
  3239. X{
  3240. X#ifdef USETITE
  3241. X    if (TI && *TI)
  3242. X        tputs (TI,1,putchr);
  3243. X#endif
  3244. X    return;
  3245. X}
  3246. void
  3247. termlib_reset()
  3248. X{
  3249. X#ifdef USETITE
  3250. X    if (TE && *TE)
  3251. X        tputs (TE,1,putchr);
  3252. X#endif
  3253. X    return;
  3254. X}
  3255. END_OF_FILE
  3256. if test 26055 -ne `wc -c <'term.c'`; then
  3257.     echo shar: \"'term.c'\" unpacked with wrong size!
  3258. fi
  3259. # end of 'term.c'
  3260. fi
  3261. echo shar: End of archive 8 \(of 13\).
  3262. cp /dev/null ark8isdone
  3263. MISSING=""
  3264. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  3265.     if test ! -f ark${I}isdone ; then
  3266.     MISSING="${MISSING} ${I}"
  3267.     fi
  3268. done
  3269. if test "${MISSING}" = "" ; then
  3270.     echo You have unpacked all 13 archives.
  3271.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3272. else
  3273.     echo You still need to unpack the following archives:
  3274.     echo "        " ${MISSING}
  3275. fi
  3276. ##  End of shell archive.
  3277. exit 0
  3278.